NAV Navbar

Introduction

This page provides documentation for using the Javascript audio player component directly without an accompanying web interface.

A customisable web user interface is not yet available.

Purpose

Most available web players are intended for use with video content. This adds additional complexity for features that are not required for audio-only use cases. This player component aims to provide first class audio-only playback support in modern browsers.

Several features are required to enable real-world commercial use:

Some additional features are highly desirable:

Supported formats

The player aims to supports the following audio formats:

Podcasts:

Live streams:

Text tracks:

Additional formats may be added in future releases.

Browser support

The player requires support for the HTML5 <audio> element. When loaded in browsers without <audio> support the player can still be used to load playlist data, but no playback functionality will be available and the UI layer must cater for a fallback playing mechanism, typically displaying a direct link to the audio content.

Chapters, captions, client-side ad delivery and tracking/analytics events are only supported on browsers with WebVTT support.

On browsers without native HLS support the free hls.js library can be used to add support. This library requires Media Source Extensions support.

Example: load hls.js before loading the player to add HLS support

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>

Installation & usage

Example: import the compressed player bundle

<script src="https://p2.iono.fm/bundle/latest/player.js" crossorigin></script>

Example: Create a player object, load an audio file and commence playback


// Test if bros
if ( iono.Player.supported() ) {

    // Create a new player instance with default configuraion
    player = new iono.Player();

    // When player object is ready, attach relevent actions
    player.ready(function () {

        // A button on the page named 'toggle-play' will start/stop playback
        const $togglePlay = document.getElementById('toggle-play');

        // Toggle playback when the button is clicked
        $togglePlay.addEventListener('click', function () {
            player.togglePlay();
        });

        // Load a single audio file item 
        player.load( 'https://example.com/test.m4a' );
    }
}

The player is provided as a compressed Javascript bundle.

To use the player, simply include it as an external script, which will make the iono.Player class available on the window.

After the external script is loaded, your Javascript can instantiate a new iono.Player object and start using it's functions to load content and start playback.

Several configuration options are available during player creation and the load function accepts a large variety of input options.

version

Example: get the version of the player object

iono.Player.version();

The player versioning uses the standard MAJOR.MINOR.PATCH convention, for example 1.0.0 would be the first full production release and 1.0.1 the first hotfix release thereafter.

Find the changelog here.

playbackSupported

Example: determine if the current browser supports native playback

iono.Player.supported();

Static function that indicates whether the player is supported on the current browser. Returns true if yes, false if not.

destroy

Example:

player.destroy())

Destroys an previously created player instance.

States & errors

The player maintains an internal global state that can be retrieved at any time. The state is not set directly but results from actions taken on the player.

State Description
empty No playlist is loaded. Default state of player after instantiation.
loading Playlist data is being loaded. Triggered by a call to load.
idle A valid playlist is loaded and playback is available.
playing Content playback is currently active.
adplaying Ad playback is currently active.
waiting Content or ad playback is stalled while data is being retrieved. UI objects can display the traditional "Buffering.." messages during this state.
paused Content or ad playback is available but has been paused by the user.
error A critical error occured.

The player may trigger error events at any stage but only proceeds to the error state when the issue is critical and playback cannot continue.

getState

Example: get the current global state of the player

currentState = player.getState();

Return the current player state as a string.

Errors

Error objects passed from the player contains an error code and optional message.

Name Type Description
code object String identifier of the error.
message array Longer description of the error if available.

The code value can be:

Error Description
ERR_NO_HTML5 Browser does not support HTML5 Audio. This is a critical error. Playback functionality will not be available.
ERR_NO_VTT Browser does not support WebVTT. Tracking, chapters and captions will not be available.
ERR_PLAYLIST_LOAD Loading of the playlist failed. This is a critical error.
ERR_PLAYLIST_ITEM Loading of a single playlist item failed. Other items may still be loaded.
ERR_NETWORK A network error occurrred while retrieving data. Access may be retried.
ERR_SRC_MISSING The source file returned a 404. Access may be retried, but likely to fail.
ERR_SRC_INVALID The source file contained invalid data.
ERR_SRC_FAILED Failed to load specified audio source. Timeout or 5xx requesting audio source. Access may be retried.
ERR_SRC_DECODE Failed to decode the received source audio data. Data may be incompatible.
ERR_INVALID_SEEK Seek requested out of audio range or on live-stream.
ERR_UNKNOWN An unknown error occurred. Default option when an error occured but no more specific data is available.

getError

Example: returns the last error

lastError = player.getError();

Return the last error that occured.

Config options

Example: create a player with custom options

player = new iono.Player({
  analytics: {
    url: 'https://example.com/tracking?v=<version>&content=<contentType>&action=<event>&title=<title>&position=<position>&uniqueuser=<uuid>&cachebuster=<cb>&file=<url>',
    events: {
      start: true,
      complete: true,
      progress: false
    }
  },
  language: 'swh',
  mute: false,
  playbackRate: 1.1,
  preload: true,
  repeat: 'playlist',
  volume: 0.5,
  qualityLevel: 'high',
  gdpr: true
});

The player has several global configuration options. Values for these options can be provided during the player's creation or using setter functions later.

Option Type Default Description
analytics object Empty Sub-object that determines playback analytics behaviour.
language string en Text track and error message language to load.
license string null Your player license key, obtained from iono.fm.
mute bool false Mute playback without changing volume level.
playbackRate float 1.0. Audio playback speed. Valid values from 0.5 to 4.0.
preload boolean false Enable or disable audio preload.
qualityLevel string medium Player will load audio tracks at this level when available. Default:
repeat string none Repeat mode for playlist. Can be none, playlist or single.
volume float 1.0 Output volume level. Valid values from 0.0 to 1.0. Not applicable on iOS.
gdpr boolean or object false Whether the user has given consent, or an object containing a user consent string.
googleAnalytics object Empty Sub-object that configures Google Analytics on the player
nowPlaying object Empty Sub-object that configures the polling for metadata on live sources
hlsjs object Empty Sub-object containing the hls.js configuration.
userConsent boolean or object true User consent configuration, true to consent to all sections, false to disable consent to all sections, and an object to fine-tune the configuration.

The analytics settings:

Option Type Default Description
url string Empty Custom URL endpoint to call with playback analytics.
events object Empty Enable or disable which playback analytics events are fired.

For more details, see the Playback Analytics section.

The googleAnalytics setting provides the following options:

Option Type Default Description
enabled boolean false Enable or disable Google Analytics tracking on the player

An object can be passed as the value for gdpr in which case it should include:

Option Type Description
userConsent string A valid user consent string.

The nowPlaying setting provides the following options:

Option Type Default Description
interval number 20000 How often (in ms) to poll for new metadata
maxHistory number 20 The number of items to keep in the now playing hostory
fetchArtwork boolean true Enable or disable automatic fetching of artwork from an artwork service

The userConsent setting allows an object for more fine-tuned configuration of user consent:

Option Type Default Description
advertising boolean true Enable or disable advertising features which may store data on the users device
analytics boolean true Enable or disable analytics features which may store data on the users device
preferences boolean true Enable or disable preference features which may store data on the users device

setLanguage

Example: change the active text track language to Swahili

player.setLanguage( 'swh' );

Changes the active text track language to use. Only text tracks that match the specified language will be loaded for playlist items. This must be a valid ISO-639 language code.

getLanguage

Example: get the current text track language

player.getLanguage();

Returns the current language setting.

setMute

Example: mute and then unmute playback

player.setMute(true);  // Mute playback
player.setMute(false); // Unmute playback

Mutes or unmutes current playback. Accepts a boolean parameter to indicate new muted status. Mute does not affect the volume level.

getMute

Example: determines if playback is currently muted

player.getMute();

Returns true if player is currently muted or false if not.

setPlaybackRate

Example: speed up playback rate

player.setPlaybackRate( 1.2 );

Sets the playback rate of audio. Normal speed is 1.0 and the player allows slow-down up to 0.4 and speed up to 3.0. Values above or below this range will be capped.

getPlaybackRate

Example: get the current playback rate

player.getPlaybackRate();

Returns the current playbackRate setting.

setPreload

Example: set player to preload playlist items

player.setPreload( true );

Enables pre-loading of items.

getPreload

Example: get the current preload setting

player.getPreload();

Returns the current preload setting.

setRepeat

Example: set player to loop single playlist item

player.setRepeat( 'single' );

Changes the repeat mode for the player.

Mode Description
none Don't repeat, stop when end of playlist is reached. (Default)
playlist Restart playlist from first item after playing the last item.
single Repeat a single playlist item.

getRepeat

Example: get the repeat mode

player.getRepeat();

Returns the current repeat setting.

setVolume

Example: set volume to 50%

player.setVolume( 0.5 );

Sets the playback volume of audio. Full volume is 1.0 and silence is 0.0.

May not be available on all platforms, for example iOS disables volume control from Javascript.

getVolume

Example: get the current playback volume

player.getVolume();

Returns the current volume setting.

setQualityLevel

Example: set player to play 'low' quality version when available

player.setQualityLevel( 'low' );

Playlist items can specify multiple audio tracks at different quality levels. When playing an item the player will always attempt to play the preferred quality level, if available.

Available quality levels: low, medium, high. See playlist audio tracks for more details.

getQualityLevel

Example: get the quality level

player.getQualityLevel();

Returns the current qualityLevel setting.

getQualityLevels

Example: get the list of currently available quality levels

player.getQualityLevels();

[
    {
        label: 'high',
        bitrate: 64000
    },
    {
        label: 'medium',
        bitrate: 32000
    }
]

Returns the list of qualityLevel options available for the current playlist item.

setAnalyticsLabel

Example: use the audio file URL instead of the playlist item title as the analytics event labels

player.setAnalyticsLabel( '<url>' );

Changes the event label to use when sending analytics data.

setAnalyticsCategory

Example: use a hardcoded title for the analytics event category instead of the content type

player.setAnalyticsCategory( 'Audio playback' );

Changes the event category to use when sending analytics data.

setAnalyticsURL

Example: set a URL to enable sending analytics to a custom service

player.setAnalyticsURL( 'https://example.com/submit' );

Set a URL to enable sending analytics to a custom service. Custom analytics not sent if no URL is specified. Recommend that this is always an HTTPS endpoint.

setGDPR

Example: update player configuration to indicate user has given consent

player.setGDPR(true);

Example: update player configuration to include a user consent string

player.setGDPR({
  userConsent: 'MWOFNAORF'
});

Modifies the current GDPR configuration, takes a boolean for simple consent, or an object containing a userConsent string.

setUserConsent

Example: update player configuration to indicate user has denied all consent options

player.setUserConsent(false);

Example: update player configuration to indicate user has granted all consent options

player.setUserConsent(true);

Example: update player configuration to indicate user has granted certain consent options

player.setUserConsent({
  advertising: true
});

Playlist structure

On a high level the player always works with a list of one or more playlist items. A playlist is set by a call to load.

Each playlist item encapsulates all the data necessary to play it's audio, display associated metadata and optionally retrieve and play ads. This section describes the playlist structure in full, but the playlist load function provides various short-hand ways of loading playlists.

Playlist

Example: podcast playlist with metadata and links:

{
  metadata: {
    contentType: 'playlist',
    title: 'Podcast show name',
    url: 'https://example.com/playlist?skip=<skip>&limit=<limit>'
  },
  syndicators: [
    {
      service: "apple",
      url: 'https://podcasts.apple.com/podcast/1'
    }
  ],
  items: [
    {
      metadata: {
        contentType: 'podcast',
        uid: 'example:string:identifier:1',
        duration: 123.5,
        language: 'en',
        title: 'Episode 1 short title',
        description: 'Longer episode description string',
        creator: 'Podcaster name',
        grouping: 'Podcast show name',
        publishDate: '2019-03-24T09:12:09+00:00',
        url: 'https://example.com/episode-home-page/1',
        icons: [
          {
            size: 'small',
            url: 'https://example.com/episode/1/300x300.jpg'
          },
          {
            size: 'medium',
            url: 'https://example.com/episode/1/600x600.jpg'
          }
        ]
      },
      audio: [
        {
          url: 'https://example.com/episode1.low.m4a',
          bitrate: 64000,
          quality: 'low',
          filesize: 123000,
          mime: 'audio/mp4; codecs="mp4a.40.5"',
          download: 'https://dl.example.com/episode1.low.m4a?download=1',
        },
        {
          url: 'https://example.com/episode1.medium.m4a',
          bitrate: 128000,
          quality: 'medium',
          filesize: 456000,
          mime: 'audio/mp4; codecs="mp4a.40.2"',
          download: 'https://dl.example.com/episode1.medium.m4a?download=1',
        }
      ]
    }
  ]
}

The simplest way to load a playlist is by passing an array of playlist items to load. Alternatively a playlist object may be passed to the same function allowing you to provide playlist metadata.

Name Type Description
metadata object Required. Metadata for the playlist item.
metadata.contentType string Required. Must be set to playlist for the player to recognize it as a playlist object and load it accordingly.
metadata.title string An optional Playlist title, which will be displayed as the playlist title in the UI.
metadata.url string The playlist url which may provide pagination if it contains one of the <skip> or <limit> computed fields.
items object[] Required List of playlist items to be loaded in to the player for playback.
syndicators object[] Syndicator links used by the subscribe button to render a list of syndication links.
syndicators[].service string A syndication service id found on supported values.
syndicators[].url string The url where the user is directed to when the syndication link is clicked.

Playlist item

Example: podcast playlist item with with rich metadata, various audio and text tracks, and client-side pre-roll ads at 0 and 120 seconds of playback:

{
  metadata: {
    contentType: 'podcast',
    uid: 'example:string:identifier:1',
    duration: 123.5,
    language: 'en',
    title: 'Episode 1 short title',
    description: 'Longer episode description string',
    creator: 'Podcaster name',
    grouping: 'Podcast show name',
    publishDate: '2019-03-24T09:12:09+00:00',
    url: 'https://example.com/episode-home-page/1',
    icons: [
      {
        size: 'small',
        url: 'https://example.com/episode/1/300x300.jpg'
      },
      {
        size: 'medium',
        url: 'https://example.com/episode/1/600x600.jpg'
      }
    ],
    banners: [
      {
        size: 'medium',
        url: 'https://example.com/episode/1/600x200.jpg'
      }
    ]
  },
  audio: [
    {
      url: 'https://example.com/episode1.low.m4a',
      bitrate: 64000,
      quality: 'low',
      filesize: 123000,
      mime: 'audio/mp4; codecs="mp4a.40.5"',
      download: 'https://dl.example.com/episode1.low.m4a?download=1',
    },
    {
      url: 'https://example.com/episode1.medium.m4a',
      bitrate: 128000,
      quality: 'medium',
      filesize: 456000,
      mime: 'audio/mp4; codecs="mp4a.40.2"',
      download: 'https://dl.example.com/episode1.medium.m4a?download=1',
    }
  ],
  text: [
    {
      kind: 'chapters',
      url: 'https://example.com/chapters.en.vtt',
      language: 'en'
    },
    {
      kind: 'captions',
      url: 'https://example.com/captions.en.vtt',
      language: 'en'
    }
  ],
  links: [
    {
      kind: 'link',
      title: 'Link title',
      url: 'https://example.com/'
    }
  ],
  syndicators: [
    {
      service: "apple",
      url: 'https://podcasts.apple.com/podcast/1'
    }
  ], 
  tags: [
    {
      service: 'google',
      name: 'dimension1',
      value: 'username'
    },
    {
      service: 'google',
      name: 'metric1',
      value: '123'
    }       
  ],
  ads: [ 
    {
      position: 0.0,
      metadata: {
        contentType: 'ad-client'
      }
    },
    {
      position: 0,
      metadata: {
          contentType: 'ad-server',
          uid: 'urn:ionocm:ad:1133',
          duration: 30.016,
          title: 'Advertisement title',
          description: 'Adverisement description'
          url: 'https://iono.dev/ad/1133',
          creator: 'iono.fm',
          grouping: 'iono.fm',
          url: 'https://iframe.iono.dev/ads/link/1'
      },
      companions: [
          {
              type: 'image',
              url: 'https://iframe.iono.dev/ads/image/1?size=300x250',
              width: 300,
              height: 250
          },
          {
              type: 'image',
              url: 'https://iframe.iono.dev/ads/image/1?size=320x50',
              width: 320,
              height: 50
          }
      ],
      links: [],
      tags: [
          {
              service: 'google',
              name: 'dimension9',
              value: '<uid>'
          }
      ],
      audio: [
          {
              url: '/tests/media/podcast.test.m4a?static-ad',
              mime: 'audio/mp4',
              filesize: 110653
          },
          {
              url: '/tests/media/podcast.test.mp3?static-ad',
              mime: 'audio/mp3',
              filesize: 119819
          }
      ]
  } 
  ]
}

Each playlist item requires at minimum one audio track. Additional audio tracks, metadata, and text tracks can be specified along with it.

Name Type Description
v string Required. Version of playlist item. The current version is 1. Future versions may add, removed or alter the playlist item structure.
metadata object Required. Metadata for the audio content.
audio[] array Required. One or more audio files or streams for the item.
companions[] array Zero or more companion ads to display in conjunction with an audio ad.
text[] array Zero or more text tracks associated with the content.
links[] array Zero or more additional links for the content, for example locations of "Now Playing" metadata for live-streams or pre-rendered waveform data for podcasts.
tags[] array Zero or more data fields to include with analytics data for the content.
ads[] array Client-side ad slots or server-side (stitched) audio advertisements.
syndicators object[] Syndicator links used by the subscribe button to render a list of syndication links.
syndicators[].service string A syndication service id found on supported values.
syndicators[].url string The url where the user is directed to when the syndication link is clicked.

Metadata

Tracks metadata for a playlist item to be used for display and analytics. All the metadata values except contentType and uid are optional.

Name Type Description
contentType string Required. Describes the type of item. Can be stream, podcast, ad-client or ad-server.
uid string Required. Unique identifier for audio content. Used for tracking and analytics.
url uri Online page with more detail about the content.
duration number Audio duration in floating point seconds. -1.0 indicates a continuous live stream. 0.0 indicates an unknown duration.
title string Short title for the item. For podcast content this should be the name of the episode.
description string Longer description of the item contents.
creator string Creator of the content. For podcast content this should be the name of the podcaster or radio station.
grouping string Grouping of content. For podcast content this should be the name of the show.
publishDate string Publish date time of item, mostly valid for podcast content. Must be in ISO8601 format.
explicit bool Boolean that indicates if the content contains explicit language. Defaults to false.
language string The ISO-639 language code of the audio content and it's metadata.
icons[] array Up to 3 square images associated with this item, see image structure.
banners[] array Up to 3 banner style images associated with this item, see image structure.

Content type

The player recognises these 4 content types:

Content Type Description
stream An audio live-stream.
podcast A podcast episode or stand-alone audio file.
ad-client Client-side ad, to be loaded by the player from an ad server.
ad-server Pre-inserted (stitched) ad in the audio file or stream.

Images

The image structure encapsulates one image associated with a playlist item. Providing different resolutions can allow the UI layer to load the optimal version based on viewport size.

Each playlist item can specify up to 3x square icons and 3x rectangular banners for display purposes. The player does no validation on the contents of these fields. Recommended use is for 1:1 aspect ratio icons and 1:3 aspect ratio banners.

Name Type Description
url uri The location of the image.
size string The intended viewport size for this image. Must be one of small, medium, large.

Recommendations for the three available quality strings:

Type Recommended icon Recommended banner
small 300 x 300 300 x 100
medium 600 x 600 600 x 200
large 1400 x 1400 1500 x 500

Audio

At minimum one item must be specified for the audio tracks element. Additional audio tracks with different quality and format settings may be provided.

Name Type Description
url uri Required. The location of the audio file or stream.
quality string The quality level associated with this source URL. Must be one of low, medium, high. Defaults to medium.
bitrate integer The average bitrate of the audio, in bits per second, for example 96000. Defaults to 0 (unknown).
filesize integer Size of the audio source in bytes. Optional, not valid for live-steams.
mime string Full audio MIME type. Ex: AAC High Efficiency v1 is audio/mp4; codecs="mp4a.40.5". If no MIME type is supplied, one will auto-selected based on the file extension. This may not be sufficient to accurately determine playback compatibility.
download uri URL to a downloadable version of the audio file. See also the playback download action.

Audio quality levels

Providing audio tracks at different quality levels caters for slower or expensive data networks. When the player starts playback of an item it will attempt to select the quality that is as close as possible to the current qualityLevel option.

When the named quality level is not available one of the other levels will be selected for playback, starting from low, then medium and lastly high.

Text

Adding text tracks are optional. Zero or more text tracks can be specified for content or ad audio.

Name Type Description
kind string Required. Kind of text track, currently supports one of each chapters, subtitles and captions.
url uri Required. The location of the text track. Must be a valid WebVTT file.
language string The ISO-639 language code for the track. Defaults to en if not specified.
label string Optional description of the track for display purposes.

Tags

Analytics data may require additional data fields that are not included in the normal playlist data structure. These can be provided as an array of values to be included in analytics requests.

Name Type Description
service string Required. Name of service. Currently supports google for targeting Google Analytics output and custom for custom URL service.
name uri Required. Name of the data field to track, for example dimension3.
value string Required. Value for this field.

Optional links can be added for the player to consume and use.

Name Type Description
kind string Required. Type of link, currently supports: like, nowplaying, waveform,link`.
url uri Required. The full link URL.

The player currently recognises these link types:

Kind Description
nowplaying URL that can be polled continuously to provide "Now Playing" metadata information for live streams. See Now Playing appendix.
waveform URL that can provide pre-rendered waveform data for display. Only valid for podcast content. See UI waveform section.
like URL to like on a social media platform.
link Link to a URL associated with the playlist item.

Ads

Example: server-side (stiched) ads, a 10 second pre-roll and 20 second mid-roll:

ads: [ 
  {
    position: 0.0,
    metadata: {
      contentType: 'ad-server',
      uid: 'ad:1',
      duration: 10.0,
      title: 'Pre-roll title',
      description: 'Longer ad description string',
      url: 'https://example.com/ad/1',
      icon: 'https://example.com/ad/1.jpg'
    }
  },
  {
    position: 60.0,
    metadata: {
      contentType: 'ad-server',
      uid: 'ad:2',
      duration: 20.0,
      title: 'Mid-roll title',
      description: 'Longer ad description string',
      url: 'https://example.com/ad/2',
      icon: 'https://example.com/ad/2.jpg'
    }
  }
]

Each ad structure stores values required to load client-side ads or track server-side (stitched) ads. This structure specifies a new position value but otherwise re-uses the metadata, audio and text structures already used for the main playlist item.

Name Type Description
position number Position of ad in the audio content, as floating-point seconds offset from start.
metadata object Metadata values for ad for display and tracking.
audio[] array One or more audio files or streams for the item content.
text[] array Zero or more text tracks associated with the ad.
links[] array Zero or more additional links for the ad.
tags[] array Zero or more data fields to include with analytics data for the ad.

Two types of ads are supported:

Additional text tracks can be provided for ad specific chapter markers or captions.

Playlist loading

Before any playback can commence the player needs to load a playlist of 1 or more playlist items.

The load function is used to perform this action and accepts different inputs:

  1. Direct audio file URL. Creates a playlist item, populating some metadata from the URL structure.
  2. Playlist URL. Loads a compatible JSON playlist from a remote URL.
  3. Playlist object. A valid playlist object passed directly in Javascript.
  4. RSS feed URL. Loads a playlist from RSS with some metadata auto-populated.

Consecutive calls to load replaces the current playlist. To add additional items to a loaded playlist use the playlist add function.

Load can be called any time during the player lifecycle, but currently playing audio will be stopped and unloaded.

Load can be called in the ERR_NO_HTML5 error state to retrieve playlist data, but will not be able to perform playback actions. This is useful for rendering a fallback UI that still has access to the playlist data.

load

Loads one or more playlist items into the player.

Parameters

Name Type Description
input mixed URL or JSON object.
options object List of options.

The options parameter is optional and can used to control playlist initialisation for some inputs:

Name Type Description
input_type string Informs the player how to parse the input field. Supported values are json for a valid playlist in JSON, rss for an RSS feed and podcast or stream for direct media URLs.
skip integer Set the starting skip value for playlists, defaults to 0. Only used when loading a playlist from a json URL.
limit integer Set the starting limit value for playlists, defaults to 20. Only used when loading a playlist from a json URL.

The options.sort option only applies to iono.fm website urls, and may be one of the following values:

Value Description
none (Default) Load only the latest episode, no other playlist items.
latest Latest episodes first.
today Episodes published today, newest first.
yesterday Episodes published yesterday, newest first.
popular_week Most popular episodes from the past week.
popular_month Most popular episodes from the past month.
popular_3_months Most popular episodes from the past 3 months.

The input parameter can be one of:

1. Input: Direct audio file URL

Example: load an audio url directly, populating playlist item defaults.

player.load('https://example.com/audio.mp3');
// or ...
player.load('https://example.com/audio', { input_type: 'podcast' });

This loads one direct stream or podcast URL for playback. Internally the player will create a playlist item for this, with fields auto-filled:

Metadata Value
contentType From options.input_type parameter, must be stream for live-streams or podcast for audio files.
uid A one-way hash created from the full URL string.
url The full original URL provided.
duration Defaults to unknown (0.0) until content is played.
title Set from the last name part of the URL. Ex: http://example.org/filename.m4a would provide filename.
description Not set.
language Defaults to en.
icons Not set.
banners Not set.

A single audio track is also auto-filled:

Name Value
url The full original URL provided.
quality Defaults to medium.
bitrate Defaults to 0.
filesize Defaults to 0.
mime Attempts to look up the MIME type based on the file extension of the URL. Uses MIME type table for matching.

2. Input: Playlist URL

Example: load a simple playlist from a remote playlist api

player.load('https://example.com/playlist123.json');

Example: load a playlist, with a URL tthat supports pagination, defaulting to the first 10 items

player.load('https://example.com/playlist/123?uuid=<uuid>&referer=<referer>&skip=<skip>&limit=<limit>', {
  skip: 0,
  limit: 10
});

A complete JSON playlist is loaded from a remote URL. This mode is also the default when no input_type parameter is specified and the URL ends with .json extension.

The response from the server should contain an application/json Content-Type header and it's content body must be valid JSON that complies with the playlist item structure.

The playlist URL supports replacement of dynamic fiels that applies to all URLs.

In addition, the playlist URL also supports two additional URL parameters:

Dynamic value Content
<skip> Should skips the first X amount of items returned in a playlist. Used for pagination.
<limit> Should limit the number of items returned in a playlist. Used for pagination.

3. Input: Playlist array

Example: loading a playlist from an array of playlist items

player.load([
  {
    metadata: {
      contentType: "podcast",
      uid: "episode:1",
      title: "Episode title",
      duration: 300.0
    },
    audio: [
      {
        url: "https://example.com/file.m4a",
        bitrate: 64000,
        quality: "low",
        mime: "audio/mp3"
      }
    ]
  }
]);

A standard array can be given as input to the player. The items in this array must conform to our playlist item structure.

4. Input: Playlist object

Example: loading a playlist object in to the player

player.load({
  metadata: {
    contentType: "playlist",
    title: "Podcast show name",
    url: "https://example.com/playlist/123?skip=<skip>&limit=<limit>"
  },
  links: [
    {
      kind: "google_podcasts",
      url: "https://podcasts.google.com/podcast/1"
    }
  ],
  items: [
    {
      metadata: {
        contentType: "podcast",
        uid: "episode:1",
        title: "Episode title",
        duration: 300.0
      },
      audio: [
        {
          url: "https://example.com/file.m4a",
          bitrate: 64000,
          quality: "low",
          mime: "audio/mp3"
        }
      ]
    }
  ]
});

The items in the items array must conform to our playlist item structure.

5. Input: RSS feed

Example: loading a playlist from an RSS feed

player.load('https://example.com/feed.rss');
// or ...
player.load('https://example.com/feed', { input_type: 'rss' });

Loads an audio RSS feed as playlist data. Internally the player will create a playlist item for each RSS XML <item>, with fields auto-filled from standard RSS or iTunes-compatible fields:

Metadata Value
contentType Set to podcast.
uid From <rss:guid>.
url From <rss:link>.
duration From <itunes:duration>, defaults to 0.0.
title From <rss:title>.
description From <rss:description>.
language Set from the main <rss:channel:language>, defaults to en.
icons Sets large icon from <itunes:image>, defaults to empty.
banners Not set.

For each item a single audio track is auto-filled:

Name Value
url Set from <rss:enclosure:url>.
quality medium.
bitrate 0.
filesize Set from <rss:enclosure:length>.
mime Set from <rss:enclosure:type>.

add

Example: add an iono.fm podcast episode to the playlist

player.add( 'https://iono.fm/e/1' );

Allows additional items to be added to an already loaded playlist. It accepts the same parameters as the load function but will add more items to the current playlist instead of of replacing it.

loadMore

Example: loading more items from a remote playlist url

// loads items 11-30
player.load('/path/to/playlist.json?skip=<skip>&limit=<limit>', {
  skip: 10,
  limit: 20
});

// adds items 30-40 to the playlist
player.loadMore();

Loads more playlist items from the remote playlist url. The original playlist must be loaded as a remote playlist url, or as a playlist object with a url in its metadata, and must contain <skip> and/or <limit> placeholders. The first playlist request to return less items than the configured limit will disable future load more calls as this usually means the end of the playlist.

unload

Example: unload a previous loaded playlist

player.unload();

Clear the currently loaded playlist. The player reverts to the empty state.

Playlist functions

Playlist functions are available after a valid playlist has been loaded.

getPlaylist

Example: get the entire loaded playlist object

player.getPlaylist();

Returns the entire loaded playlist object, if any. Returns false if no playlist is loaded.

getPlaylistIndex

Example: get the index of the current playing playlist item

player.getPlaylistIndex();

Returns the index of the current playing playlist item. Returns false if no playlist is loaded.

getPlaylistItem

Example: get specific items from the playlist

player.getPlaylistItem();  // Get current item
player.getPlaylistItem(1); // Get item at index 1
player.getPlaylistItem('episode:1'); // Get item with UID 'episode:1'

Returns a single playlist item, based on the parameter:

Returns false if the index or item does not exist in the playlist.

getPlaylistMetadata

Example: get the current playlist metadata

player.getPlaylistMetadata();

Returns the metadata of the current playlist. Returns null if a playlist hasn't been loaded yet.

selectPlaylistItem

Example: switch to specific playlist items

player.selectPlaylistItem(1);           // Switch to item at 1
player.selectPlaylistItem('episode:1'); // Switch to item with UID 'episode:1'

Changes the current playlist item. Can be selected by specifying an index or an item UID.

nextPlaylistItem

Example: skip to the next item in the playlist

player.nextPlaylistItem();

Convenience function to skip to the next item in the playlist. If the player is already in the playing state the new item will play automatically. Obeys the global repeat option.

Returns the index of new playlist item that it has skipped to. Returns false if no valid playlist is loaded or the playlist is at the last item and repeat mode is none.

previousPlaylistItem

Example: skip to the previous item in the playlist

player.previousPlaylistItem();

Convenience function to skip to the previous item in the playlist. If the player is already in the playing state the new item will play automatically. Obeys the global repeat option.

Returns the index of new playlist item that it has skipped to. Returns false if no valid playlist is loaded or the playlist is at the first item and repeat mode is none.

Playback functions

Functions used to manipulate playback and get information about current playback.

play

Example: play the current playlist item

player.play();

Start or resume playback of the current playlist item.

pause

Example: pause playback

player.pause();

Pause playback of the current item.

For live stream playback this function behaves the same as stop.

Note: pause() is not available while and advertisement is being played.

stop

Example: stop playback and reset to start

player.stop();

Stops playback of the current item and reset to it's start.

For live stream playback it stops retrieving new data and upon resuming will restart at the latest point of the live stream - content will not be buffered locally while stopped.

download

Example: trigger download of a file

player.download();

Helper that triggers a file download. It uses the download field specific for the currently selected audio file, falling back to the source URL if none is set. Before opening the URL it triggers a download analytics event to enable tracking user downloads.

togglePlay

Example: toggle between play and pause

player.togglePlay();

Helper that automatically toggles between play or pause based on current state.

toggleMute

Example: toggle between muted and unmuted

player.toggleMute();

Helper that automatically toggles the mute status.

isPaused

Example: checking if the player is paused or stopped.

isPaused = player.isPaused();

Helper function to check if the player is currently paused or not.

getDuration

Example: get the playback duration of the current content

player.getDuration();

Returns the playback duration of the current playlist item. Returns -1 for live streams or 0 when not known.

getPosition

Example: get the current playback position in floating point seconds.

player.getPosition(); // 0.0 is start of file, 60.0 is one minute, ..

Gets the playback position in the current playlist item as a floating point seconds value. For live stream playback this value resets after a stream is stopped and resumed.

setPosition

Example: seek to half way in a podcast file

player.setPosition( player.getDuration() / 2 );

Seeks to the given position in the current item. Requires a floating point parameter between 0.0 (start) and the total duration of the current item.

Returns:

If the player has not yet loaded the source, or is busy buffering, it will wait for playback to be ready before it performs the seek.

getBuffered

Example: get the list of loaded segments

player.getBuffered();

Returns the list of buffered audio segments are per the normal media buffered property.

getBufferedPercentage

Example: retrieve total percentage of current item already buffered

player.getBufferedPercentage();

Returns the percentage of audio data already buffered by the player from the current playing item, if any.

Returns 0 for live streams or if there is no item loaded.

Text tracks

The player supports user provided text tracks for each playlist item. Text tracks can provide chapter markers, subtitles and captions to accompany both the main content and any ad media.

Track requirements

Text tracks must be valid WebVTT files. Invalid files will be ignored.

Tracks can be provided in multiple languages and must use the ISO-639 language code to specify which language they contain.

Only one of each text track kind is supported (if multiple ones of the same kind is specified the player will always load the first one):

Track loading process

When loading a playlist item that has text track entries specified, the player will automatically load text tracks if there are any tracks for the current global language option

If this process results in any text tracks loaded successfully the player will emit the texttrackschange event.

This text track loading process for the current playlist item is triggered again when the user calls the setTextTracksEnabled() or setLanguage() functions with new parameters.

Data structures

Text track support uses two data structures: one to describe a list of available text tracks, and one to convey information on the actual text cues described inside loaded tracks.

The list of available tracks is already documented as part of the playlist structure.

The other describes one or more text cues from inside the tracks, used to provide a list of all or current cues from a loaded track.

Text cue details

Example: two chapters available for an item

{
    [
        {
            startTime: 0.00,
            endTime: 30.00,
            text: "Chapter 1"
        },
        {
            startTime: 30.00,
            endTime: 60.00,
            text: "Chapter 2"
        }
    ]
}

Native browser implementation provides the VTTCue interface but the player uses a much simplified structure to list one or more cues:

Field Description
startTime Start position of cue, in floating point seconds offset.
endTime End position of cue, in floating point seconds offset.
text Text associated with item.

Cues are typically provided within the context of a track specific event or function so does not need to specify any more data.

getTextTracks

Example: returns the list of text tracks available on current playlist item

[
    {
        kind: 'chapters',
        url: 'https://example.com/chapters.en.vtt',
        language: 'en'
    },
    {
        kind: 'captions',
        url: 'https://example.com/captions.en.vtt',
        language: 'en'
    }               
]

Helper function that simply provides the current playlist item's array of available text tracks. Can be utilised to build a list of UI options.

getChapters

Provides the complete list of text cue details loaded from a chapters track on the current playlist item, if any. Can be used to display a list of available chapters for the current playlist item.

getCurrentChapter

Provides a text cue details object from a loaded chapters track based on the current playback position. Returns zero or one entries. Can be used to display the current chapter.

getSubtitles

Provides the complete list of text cue details loaded from a subtitles track on the current playlist item, if any. Can be used to display the full transcript for the current playlist item.

getCurrentSubtitles

Provides zero or more text cue details object from a loaded subtitles track based on the current playback position. Can be used to display any currently active subtitles.

getCaptions

Provides the complete list of text cue details loaded from a captions track on the current playlist item, if any.

getCurrentCaptions

Provides zero or more text cue details object from a loaded captions track based on the current playback position. Can be used to display any currently active captions.

Advertising

The following advertisement modes are currently supported by the player:

Player ad configuration options

Example: Enable iono.fm client-side ad requests

var player = new iono.Player({
    ads: {
        enabled: true,
        requestTimeout: 5000,
        skipOffset: 10,
        rerollTimeout: 480,
        adContainer: document.querySelector('#ad-container')
    }
});

The advertising features of the player may be configured using the ads option when initialising a player instance.

Option Type Default Description
adContainer HTMLElement null An element on the DOM where ad creatives will be rendered. If not using a player ui, or the chosen layout does not provide an ad container, this value will be required to perform VAST ad requests.
enabled boolean false Whether or not to allow advertisements on the player instance.
requestTimeout number 5000 Number of milli-seconds to wait before an ad request times out. Used by VAST and client side ads only.
skipOffset number 10 Number of seconds to wait before an ad can be skipped. Client side ads only. A value of 0 will make skipping available from the start of the ad, while -1 will disable skipping of ads completely.
rerollTimeout number 480 Number of seconds to wait before an ad may be played again on the same content. Client side ads only.
adsWizzURL string null URL to retrieve companion metadata from. Adswizz in-stream ads only. TO BE CONFIRMED

iono.fm client side ads

Example: Enable a 15 second client-side pre-roll ad

player.load({
    // ...other playlist fields
    ads: [
        {
            position: 0,
            metadata: {
                uid: 'adid',
                duration: 15
            }
        }
    ]
});

In this configuration, the player requests audio ads from the iono.fm platform, with optional companion content.

To use these requires (a) enabling ads inside the player initialisation and (b) marking their positions in the playlist. These ads may be triggered as pre-rolls or anywhere inside the content.

Different ad events fire when ads are retrieved, started, while playing and upon completion - the adevents documentation the different ad related events available.

iono.fm embedded podcast ads

Example: A podcast with an embedded 20 second pre-roll ad

player.load({
    // ...other playlist item fields        
    ads: [
        {
            position: 0,
            metadata: {
                uid: 'adid',
                title: 'Advertisement title',
                duration: 20,
                contentType: 'ad-server',
                description: 'Advertisement description',
                grouping: 'Channel / Album name',
                creator: 'Provider / Artist name'
            },
            audio: [
                {
                    url: '/advert.mp3',
                    mime: 'audio/mpeg',
                    quality: 'low',
                    bitrate: 54321,
                    filesize: 12345
                }
            ],
            companions: [
                {
                    type: 'image',
                    url: '/companion.jpg',
                    width: 300,
                    height: 250
                }
            ],
            links: [
                {
                    kind: 'clickthrough',
                    title: 'Companion clickthrough link',
                    url: '/clickthrough'
                },
                {
                    kind: 'impression',
                    title: 'Companion impression url',
                    url: '/impression'
                }
            ],
            tags: [
                {
                    service: 'google',
                    name: 'dimension1',
                    value: 'foo'
                }
            ]
        }
    ]
});

For podcasts that have embedded audio ads, these are be specified inside the playlist. They can specify their location inside the podcast, duration and additional companion content. When reaching these inside the podcast content the player will treat them similar to a client-side ad.

VAST ads

Example: Loading VAST ads from a playlist item

player.load({
    // ...other playlist item fields
    ads: [
        {
            metadata: {
                contentType: 'ad-vast',
                url: 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator='
            }
        }
    ]
});

We use the Google IMA SDK to manage playback of VAST-compliant ads. To provide the necessary configuration, we load VAST ads from playlist items by looking for ads in the playlist item with the ad-vast content type. These entries require a url, which must be the adTagUrl provided by your advertising provider.

The current implementation prefers audio-only creatives. This is because we currently don't have an ad container suitable for visual ad playback in our built-in layouts which means ads with video or image creatives will not be visible to the user.
This restriction does not apply to custom players that do not use the player ui. In this case you must specify an ad container using the ads.adContainer option and ads will be rendered in that container.

We do plan to provide better support for visual ad creatives in the future, but for now it is recommended to stick with audio-only creatives if you're using one of our player ui layouts.

Advertising: Events

When an ad runs, the UI may need to respond by indicating this to the user or by displaying a companion banner. Implementors can attach to the different ad events to implement this functionality.

All advertising events contain:

For a typical ad play, this is the expected sequence of events:

Event: adstart
Event: adcompanionstart (only for ads with a companion)
Event: addurationchange (once the player know the duration of the ad break)
Event: adplaying
...
Event: adtimeupdate (fires continuously while the ad is playing)
Event: adtimeupdate
...
Event: adskippable (only fires for ads that can be skipped)
...
Event: adtimeupdate
Event: adtimeupdate
...
Event: adcompanionend (only for ads with a companion)
Event: adend

adstart

Example: adstart event

{
    uid: '1',
    position: 0,
    type: 'adstart',
    ad: { /* advertisement data */ }
}

Triggered when an advertisement slot is started. The position is in floating-point seconds, and is the position in the content where the advertisement started.

addurationchange

Example: addurationchange event

{
    uid: '1',
    type: 'addurationchange',
    duration: 30,
    ad: { /* advertisement data */ }
}

Triggered when the duration of an advertisement changes.

adplaying

Example: adplaying event

{
    uid: '1',
    type: 'adplaying',
    ad: { /* advertisement data */ }
}

Triggered when actual playback of the ad begins.

adtimeupdate

Example: adtimeupdate event

{
    uid: '1',
    position: 0,
    type: 'adtimeupdate',
    ad: { /* advertisement data */ }
}

Triggered when the ad playback position changes. The position is in floating-point seconds and indicates the current playback position inside the ad.

adcompanionstart

Example: adcompanionstart event

{
    uid: '1',
    position: 0,
    type: 'adcompanionstart',
    ad: { /* advertisement data */ },
    companion: {
        type: 'image',
        url: 'https://example.com/path/to/creative.jpg',
        width: 300,
        height: 250
    }
}

Triggered when a companion ad starts. The position should be the position in the advertisement that the companion started. Multiple adcompanionstart events may fire if there are multiple companions on an advertisement, it is up to the UI to determine which of these events to use when rendering companions.

When a companion comes from AdsWizz it's type should be iframe. The url of the companion should be loaded as an iframe source. The companion won't include dimensions, instead it will include the zoneAlias the companion is for:

Example: adcompanionstart event for an AdsWizz companion

{
    uid: '1',
    position: 0,
    type: 'adcompanionstart',
    ad: { /* advertisement data */ },
    companion: {
        type: 'iframe',
        url: 'https://example.com/path/to/creative',
        zoneAlias: 'DisplayZone',
    }
}

The zoneAlias field is used by AdsWizz companions and can be used to load companion ads in the correct location on the ui.

adcompanionend

Example: adcompanionend event

{
    uid: '1',
    position: 0,
    type: 'adcompanionend',
    ad: { /* advertisement data */ },
    companion: {
        type: 'image',
        url: 'https://example.com/path/to/creative.jpg',
        width: 300,
        height: 250
    }
}

Triggered when a companion ad ends. The position should be the position in the advertisement that the companion ended. Multiple adcompanionend events may fire if multiple companions end at the same time, it is up to the UI to determine which of these events to use when hiding rendered companions.

adskippable

Example: adskippable event

{
    uid: '1',
    type: 'adskippable',
    ad: { /* advertisement data */ }
}

Triggered when an advertisement becomes skippable. This event will only fire if the player is configured to allow skipping of advertisements using the ads.skipOffset option when creating a player instance. Additionally, this may only apply to some types of ads - ads that are replaced in-stream by the server can never be skipped.

adskip

Example: adskip event

{
    uid: '1',
    position: 5,
    type: 'adskip',
    ad: { /* advertisement data */ }
}

Triggered when an advertisement is skipped. The position should be the position in the advertisement that it was skipped.

adend

Example: adend event

{
    uid: '1',
    type: 'adend',
    ad: { /* advertisement data */ }
}

Triggered when an advertisement has ended.

Events

Numerous events are triggered during the life-cycle of the player, most of which are used either to drive an interactive UI or to enable tracking & analytics.

Events are documented by different categories:

Category Description
State & Errors Global state changes and errors that occur during the player's use.
Config Options Events relating to changes in player options.
Playlist Events relating to playlist handling.
Content playback Events relating to content media playback.
Ad playback Events relating to ad media playback.
Text tracks Events relating to text tracks.
Tracking Events for analytics tracking.

Three functions are provided to bind and unbind from player event notifications:

on

Example: bind to 'state' events

player.on( 'state', function() )

Binds an event listener to a specific player event, to be called every time the event fires.

one

Example: bind first 'state' event

player.one( 'state', function() )

Binds an event listener to a specific player event, to be called only once and then unbind automatically.

off

Example: unbind from 'state' events

player.off( 'state', function() )

Unbinds an from an event previously attached to by the on or one functions.

Events: State & Errors

Global state changes and errors that occur during the player's use.

state

Example: player changing to ready state after loading playlist

{
    type: 'state',
    currentState: 'ready',
    previousState: 'loading'
}

Fires when the global player state changes. It provides these fields:

Name Type Description
currentState string New global player state.
previousState object Previous state.

error

Example: unknown error occured

{
    type: 'error',
    error: {
        code: 'ERR_UNKNOWN',
        message: 'An unknown error occurred'
    }
}

Fires when the player encounters an error. See the list of errors.

Events: Config options

Events that fire when player configuration options or available options are changed.

languagechange

Example: default text track language changed to Swahili

{
    type: 'languagechange',
    language: 'swh',
    title: 'Swahili'
}

Fires when the default text track language is changed.

languageschange

Example: available languages changed to English and French

{    
    type: 'languageschange',
    languages: [
        {
            language: 'en',
            title: 'English'
        },
        {
            language: 'fr',
            language: 'French'
        }
    ]
}

Fires when the list of available languages changes, typically when a new playlist item becomes active. The list of available languages are determined by the available text tracks provided for an item.

ratechange

Example: playback speed increased to 20% above normal

{
    type: 'ratechange',
    playbackRate: 1.2
}

Fires when the playback speed is modified.

repeatchange

Example: repeat mode changed to 'single'

{
    type: 'repeatchange',
    repeat: 'single'
}

Fires when the playlist repeat mode is changed.

volumechange

Example: volume changed to 50% but is not muted

{
    type: 'volumechange',
    volume: 0.5,
    muted: false
}

Fires when the audio volume changes (both when the volume is set and when the muted attribute is changed). Event data includes the new volume level and the muted flag.

levelchange

Example: Current quality changed to 'medium':

{
    type: 'levelchange',
    level: {
        label: 'medium',
        bitrate: 56000
    }
}

Fires when the current preferred quality level is changed.

levelschange

Example: available quality levels changed to 'high' 64k and 'medium' 32k, auto-selected 'medium'

{
    type: 'levelschange',
    levels: [
        {
            label: 'high',
            bitrate: 64000
        },
        {
            label: 'medium',
            bitrate: 32000
        }
    ],
    level: {
        label: 'medium',
        bitrate: 32000
    }
}

Fires when the list of available quality levels changes. Typically occurs when a new playlist item becomes active.

Events: Playlist

playlistload

Example: loading of new playlist has started

{
    type: 'playlistload',
    mode: 'load',
}

Fires when loading of a playlist starts. This is fired for loading a completely new playlist with load() or when adding more items with add(). The mode value will contain the value load or add to indicate which.

playlistchange

Example: playlist load completed with 5 new items added

{
    type: 'playlistchange',
    loaded: 0,
    added: 5, 
    total: 10
}

Fires when loading of a playlist has been completed and 1 or more new items are available.

playlistselect

Example: playlist item 2 has been selected

{
    type: 'playlistselect',
    details: {
        index: 2
    }
}

Fires after a new active playlist item has been selected.

Events: Content playback

When playing content audio (different from ad audio) the player emits most of the standard browser media events.

These events are enriched with additional information compared to normal media events to simplify UI implementation. In all cases at least the unique identifier of the related item is included.

This sections lists the applicable media events and their additional event data.

durationchange

Example: content duration has been updated 30 seconds

{
    uid: 'episode:1',
    type: 'durationchange',
    duration: 30.0
}

This event fires when a new playlist item becomes active, using the duration field defined in the playlist item.

play

Example: user resumed playback after being paused at 23 seconds

{
    uid: 'episode:1'
}

Fires when the playback state is no longer paused, as a result of the play method, or the autoplay attribute.

playing

Example: content playback is active, at 23.1 seconds into podcast

{
    uid: 'episode:1'
}

Fires when the media has enough data to start playing, after the play event, but also when recovering from being stalled, when looping media restarts, and after seeked, if it was playing before seeking.

ended

Example: podcast episode playback completed

{
    uid: 'episode:1'
}

Fires when media playback completes.

pause

Example: user paused podcast playback at 23 seconds

{
    uid: 'episode:1'
}

Fires when the media playback state is paused (paused property is true). This event does not apply to live stream playback.

stop

Example: user stopped playback

{
    uid: 'stream:1'
}

Fires when the media playback is stopped. For podcast content this means that the play position has also been reset to the beginning.

progress

Example: additional media content has been loaded for a podcast

{
    uid: 'episode:1'
}

Fires periodically to provide updates of progress downloading the media. Information about the current amount of the media that has been downloaded is available from the players getBuffered() function.

seeking

Example: start seek to position 123 seconds into a podcast

{
    uid: 'episode:1',
    position: 123.0
}

Fires when a seek operation commences.

seeked

Example: seeked to position 123 seconds into a podcast

{
    uid: 'episode:1',
    position: 123.0
}

Fires when a seek operation completes.

stalled

{
    uid: 'episode:1'
}

Fires when remote data is being requested but no responses are received. Can point to a networking interruption.

timeupdate

Example: user has listened to position 123.45 of a podcast

{
    uid: 'episode:1',
    position: 123.45
}

Fires continuously during playback, typically every 250ms, to indicate an updated listening position.

Events: Text Tracks

Events fired for text tracks.

texttrackschange

Example: English chapters and subtitles tracks are loaded from playlist

{
  "type": "texttrackschange",
  tracks: [
    {
      kind: 'chapters',
      url: 'https://example.com/chapters.en.vtt',
      language: 'en',
      mode: 'showing'
    },
    {
      kind: 'chapters',
      url: 'https://example.com/captions.fr.vtt',
      language: 'fr',
      mode: 'disabled'
    },              
    {
      kind: 'subtitles',
      url: 'https://example.com/subtitles.en.vtt',
      language: 'en',
      mode: 'showing'
    },
    {
      kind: 'subtitles',
      url: 'https://example.com/subtitles.fr.vtt',
      language: 'fr',
      mode: 'disabled'
    }   
  ]
}

The list of loaded text tracks have changed. Fires after a text track loading process completes. Contains the list of text tracks as specified in the playlist item text field with an additional mode field that indicates which items has been loaded.

Name Type Description
kind string Required. Kind of text track, currently supports one of each chapters, subtitles and captions.
url uri Required. The location of the text track. Must be a valid WebVTT file.
language string The ISO-639 language code for the track. Defaults to en if not specified.
label string Optional description of track for display purposes.
mode string Set to showing for tracks that have been loaded and disabled for tracks that have not been loaded.

textcuechange

Example: current active cues have changed with 1 new cue active on the loaded subtitles track

{
  "type": "textcuechange",
  "track": {
    "kind": "captions",
    "language": "en"
  }
  "currentCues": [
    {
      "startTime": 0.00,
      "endTime": 10.00,
      "text": "Hello World!"
    }
  ]
}

Fires when the currently active text cue is changed as a result of playback. One event fires per loaded text track.

Events: Tracking

The player emits tracking events that can be used to drive ad and listening analytics:

  1. Action tracking events are driven by user interaction,
  2. Position tracking events are emitted when playback reaches specific playback positions or durations.

To simplify analytics integrations, tracking events always fire in addition to any normal playback events that are fired for UI updates. For example, starting a podcast triggers the media playing event but also action:play tracking event.

Tracking events can be used to implement analytics modules, but the player already includes a playback analytics layer for sending data to Google Analytics or a custom endpoint.

tracking

Example: playback reached first quartile (25%) of a 30-second static ad

{
    type: 'tracking',
    details: {
        event: 'position',
        contentType: 'ad-server',
        uid: 'ad:1',
        position: 7.5,        
        percent: 25,
        interrupted: false
    }
}

Example: playback reached last quartile (75%) of a 30-second static ad, but was interrupted during playback

{
    type: 'tracking',
    details: {
        event: 'position',
        contentType: 'ad-server',
        uid: 'ad:1',
        position: 7.5,        
        percent: 25,
        interrupted: true
    }
}

Example: live stream playback reached 2 minutes

{
    type: 'tracking',
    details: {
        event: 'position',
        contentType: 'stream',
        uid: 'stream:1',
        position: 120.0,
        interrupted: false        
    }
}

Example: user clicked pause at 30 seconds of a podcast

{
    type: 'tracking',
    details: {
        event: 'action',
        contentType: 'podcast',
        uid: 'episode:1',
        position: 30.0,
        action: 'pause',
        interrupted: false    
    }
}

Event structure

Tracking events consist of these data fields:

Name Type Description
event string Type of tracking event: action or position
contentType string Type of content
uid string Unique identifier from playlist item
action string (Only for action events) One of the list of defined tracking actions
position string (Only for position events) Playback position in floating point seconds
percent string (Only for position events on items with a set duration) Percentage of item reached
interrupted bool Set to true if any content of the current playback item has been interrupted

interrupted flag

The VAST Ad tracking standard requires that tracking events indicate when:

Action events

The list of action tracking events that fire is defined by typical tracking use cases:

Position events

Position events fire based on current listening position. The event interval is determined by the type of content being played:

Content Type Interval
stream Fires every 30 seconds of playback
podcast Fires every 10% percent of playback reached
ad-server, ad-client Fires every 25% percent of playback reached

Playback Analytics

The player provides an analytics layer that listens to the core tracking events and triggers analytics data events to supported services.

Playback events

The list of events that can trigger calls to analytics backends:

Event Names Default Details
start Enabled Audio playback started.
complete Enabled Playback reached the end of the content. Only fired for podcast content.
progress Enabled Playback position reached. Tracked once per minute for live-stream content and every 10% of podcast playback.
pause Disabled The user paused playback.
resume Disabled The user resumed playback after pausing.
mute Disabled The user activated the mute control.
unmute Disabled The user deactivated the mute control.
seek Disabled The user skipped forward or backwards in content. It's position data will indicate the start of the seek. Does not apply to live streams.
adskip Enabled The user skipped an advert. It's position data will indicate the start of the skip. Only applies to ads.

Each time one of these events fire, if enabled, the player will call one or more analytics services with a configurable set of data.

The analytics field of the player configuration options can determine which of these analytics events are fired.

Dynamic data fields

A range of data fields are available to the player to send as part of an analytics URL. Some dynamic fields are also available to other URLs the player calls (like playlist or audio source URLs). These field values are either "dynamic" (created by the player and available only the client side) or "playlist" values (values as retrieved from the active playlist item).

Available only in analytics tracking events:

Dynamic value Content
<event> The event that occured, one of the playlist event names from the previous table.
<quality> The active playback quality level.
<format> The active audio codec format.
<url> The active audio source URL.
<position> The current playback position in the audio source, in foating point seconds.
<percent> The current playback percentage in the audio source. (Not available for live streams)
Playlist value Content
<uid> Set from the current playlist item uid field.
<contentType> Set from the current playlist item contentType field.
<title> Set from the current playlist item title field.
<creator> Set from the current playlist item creator field.
<grouping> Set from the current playlist item grouping field.
<publishDate> Set from the current playlist item publishDate field.
<duration> Duration of the content. (Not valid for live streams)

Available in analytics tracking events and in other URLs:

Dynamic value Content
<version> The version of the player that sent the event data.
<sid> The current session identifier, as provided by getSID. Helps tracking unique sessions.
<uuid> The current unique user identifier, as provided by getUUID. Helps tracking unique listeners.
<cb> A randomised value to prevent browser caching.
<muted> The current muted status.
<volume> The current volume level.
<playbackRate> The current playback rate.
<referer> The current HTTP Referer.

Updating URLs with tracking data fields

Example: load a playlist item with tracking data expanded inside:

player.load( 'https://example.com/playlist.json?session=<sid>&uniqueuser=<uuid>', {input_type: 'stream'} );

To use these fields in URLs or inside playlist data, they must be encapsulated inside the < > brackets. The player will automatically recognise and substitute these values in certain URLs:

Service: Google Analytics

Example: initialise Google Analytics via jtag.js (recommended)

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXX-X"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'UA-XXXXXXXX-X');
</script>

Example: initialise Google Analytics via analytics.js (legacy)

<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXXX-X', 'auto');
ga('send', 'pageview');
</script>

Example: use the playlist item to override the 'eventCategory' field, track two custome dimensions and one custom metric in Google Analytics events

tags: [
    {
        service: 'google',
        name: 'eventCategory',
        value: '<url>'
    },
    {
        service: 'google',
        name: 'dimension1',
        value: 'someusername'
    },
    {
        service: 'google',
        name: 'dimension2',
        value: '<position>'
    },
    {
        service: 'google',
        name: 'metric1',
        value: 123
    } 
]

The player supports sending data directly to Google Analytics. TO enable this a GA snippet needs to be initialised on the page. The player supports both the modern Google Tag Manager and the older analytics.js snippet.

Google Analytics defines 4 standard event fields, which are populated as follows by default:

Event Field Content
eventCategory The <contentType> of the current playlist item. For example podcast or ad-client.
eventAction The <event>. For example start or progress.
eventLabel The <title> field of the current playlist item, except for progress events, where it sends the <position> in minutes for live-streams or <percent> for other content.
eventValue The playback <position> value in seconds.

Using custom values & dimensions

Sometimes different values may be required for the standard Google Analytics fields. Additionally, sometimes there may be a need to specify custom dimensions and metrics. To do this, send additional tags in the playlist item marked for service: google. See the associeated example for a playlist item that overrides the eventCategory value, specifies 2 custom dimensions and one custom metric.

Service: Custom Endpoint

Example: enabling a custom analytics endpoint with all the values we require analytics.url configured to 'https://example.com/tracking'

player.setAnalyticsURL( 'https://example.com/tracking?v=<version>&content=<contentType>&action=<event>&title=<title>&position=<position>&uniqueuser=<uuid>&cachebuster=<cb>&file=<url>' );

Example: adding two values to the existing custom tracking URL

tags: [
    {
        service: 'custom',
        name: 'username',
        value: 'johndoe'
    },
    {
        service: 'custom',
        name: 'contentid',
        value: '<uid>'
    }
]

In addition to Google Analytics, the player can also send analytics data to a custom endpoint. By default this is disabled unless a valid URL has been provided in the analytics.url config option (or set manually).

When using a custom URL, the following rules apply:

Using custom values

Similar to Google Analytics, additional custom values can be provided for each playlist item. These should be added to the playlist item tags with the service field set to custom.

The analytics engine will append these as URL parameters to the custom tracking URL.

Implementing a custom endpoint service

Requirements and recommendations for implementing a service endpoint to receive this tracking data:

Player UI

Include base UI library and the required "layout"

  <!-- Include the base UI library -->
  <script src="https://p2.iono.fm/bundle/latest/player-ui.js" crossorigin></script>

  <!-- Include the 'legacy' layout -->
  <script src="https://p2.iono.fm/bundle/latest/layouts/legacy.js" crossorigin></script>

The player provides user interface modules to enable quick integration into most layouts. When using the user interface component implementors can still bind to all documented events, though this should not be necessary.

To start using the user interface, include the required base UI library and the specific layout to use.

Layouts

Several "layouts" are supported. The layout determines the overall size and structure of the view, though each layout can still be themed and controlled in various ways.

"legacy"

A compact rectangular layout, ideal for embedding inside sidebars or other limited spaces.

Based on original layout. To be renamed

Does not yet support waveform displays.

Supports podcast and stream content.

"square"

A large square layout, ideal for single-page views that highlight a specific piece of content.

Supports pre-rendered waveform displays for podcasts.

Supports podcast and stream content.

Configuration options

Several configuration options can be provided in the player configuration under the "ui" section to adjust how it is displayed:

Initialise a player UI with UI config options

const player = new iono.Player.UI(document.getElementById('player'), {
  source: 'https://example.com/test.mp3',
  ui: {
    layout: 'legacy',
    contentType: 'podcast',
    language: 'en',
    sharing: false,
    artwork: true,
    playlist: true,
    download: false,
    description: true,
    waveform: true
  }
});
Name Type Default Description
artwork boolean true Enables or disables showing of artwork.
branding string / boolean true Changes the branding element. true show the iono.fm logo, false hides the element, or a string to an image URL. Only available if license allows it.
contentType string podcast The type of content the player will be playing. Can be stream or podcast.
dateTimeFormat string j M ga The format to apply to publish dates displayed on the ui. See Date and time formatting for more info.
description boolean true Enables or disables showing the description section.
download boolean false Enables or disables downloading of audio sources.
language string en The language used for display text. Currently supports only en, more languages to be available soon.
layout string legacy The UI layout to use. See previous section for details.
playlist boolean true Enables or disables showing the playlist section.
sharing boolean false Enables or disables the "Sharing" control.
theme object Theming options, such as colours, see Theme options for more information.
waveform boolean true Enables or disables waveform rendering.

Theme options

These options configure the look of the ui such as colours and rounding.

Initialise a player UI with a custom theme

const player = new iono.Player.UI(document.getElementById('player'), {
  source: 'https://example.com/test.mp3',
  ui: {
    theme: {
      rounded: 10,
      background: '000000',
      text: 'ffffff',
      accent: 'ffff00',
      border: 'cccccc'
    }
  }
});
Name Default Description
background ffffff Sets the background fill colour as a Hex value.
text 000000 Sets the text colour as a Hex value.
border - Sets the border colour as a Hex value. If not provided, automatically calculated from background and text.
accent ee3b96 Sets the highlight colour as a Hex value. Used on key components like the "Play/Pause" button.
rounded 0 Set the border radius in pixels. Value can be between 0 (square) to 20

Date and time formatting

The publish dates displayed on the ui can be formatted using the dateTimeFormat option. This option takes a string which defines the desired format of displayed dates.

Key Output Description
Y 2020 A full numeric representation of a year, 4 digits
n 1 - 12 Numeric representation of a month, without leading zeros
m 01 - 12 Numeric representation of a month, with leading zeros
M Jan A short textual representation of a month, three letters
F January A full textual representation of a month
j 1 to 31 Day of the month without leading zeros
d 01 - 31 Day of the month, 2 digits with leading zeros
g 1 - 12 12-hour format of an hour without leading zeros
h 01 - 12 12-hour format of an hour with leading zeros
G 0 - 23 24-hour format of an hour without leading zeros
H 00 - 23 24-hour format of an hour with leading zeros
i 00 - 59 Minutes with leading zeros
s 00 - 59 Seconds with leading zeros
a am, pm Lowercase Ante meridiem and Post meridiem
A AM, PM Uppercase Ante meridiem and Post meridiem

Waveforms

Create a waveform in binary .dat format with 1 pixel per second resolution

audiowaveform -i <inputfile> -o <outputfile>.dat --pixels-per-second 1

Link to a waveform file in the playlist "links" section

{
    links: [ 
        {
            kind: 'waveform',
            url: 'https://example.com/waveform/episode.1.dat',
        }               
    ],  
}

Use the BBC library to allow oading/parsing of waveform data

<!-- Allows using BBC audiowaveform data -->
  <script 
  src="https://cdn.jsdelivr.net/npm/waveform-data@2.1.2/dist/waveform-data.js"
  integrity="sha256-qBMNRpnDJSLPikbNivJghDhO+3bWgiD2kz2AoSYwghI=" 
  crossorigin="anonymous">
  </script>

The player supports displaying an audio waveform for podcasts in place of the normal scrub bar. To use this functionality:

Playlist pagination and infinite scroll

The player playlist component now supports pagination of the playlist, allowing users to load more content from the server when the end of the playlist is reached.

This functionality is only enabled when:

At the bottom of the playlist, a "Load More" button allows users to retrieve the next set of results from the server. The player uses the skip and limit parameters in the playlist URL to retrieve the next set of results and adds this to the playlist area. Under supporting browsers, this functionality is triggered automatically when reaching the bottom of the playlist, allowing for an "infinite scroll" user experience. When a paginated request returns an empty playlist, this functionality is disabled, prevent unnecessary loading operations.

The playlist component allows searching the contents of it's current playlist. A small search icon is shown and clicking on a result will start playing it. Currently a basic case-insensitive search is performed on playlist items' title field.

Integration: AdsWizz

Setup

AdsWizz needs to maintain a listenerId which identifies a listener and is attached to all requests to the AdsWizz platform.

Example: Load the AdsWizz libaries for listener id management

<script src="http://synchrobox.adswizz.com/register2.php"></script>
<script src="http://cdn.adswizz.com/adswizz/js/SynchroClient2.js"></script>

AdsWizz provides two scripts which provide methods for getting and setting the listenerId.

Example: Use functions from the AdsWizz libraries to decorate the stream URL

var streamUrl = 'http(s)://<streaming_server>:<live streaming port>/stream';
var playbackUrl = com_adswizz_synchro_decorateUrl(streamUrl);

// http(s)://<streaming_server>:<live streaming port>/stream?listenerId=f28fece93d9169a29e4f103d1483b9a825f19c2a94d198f284cb3561bbd4c&awparams=companionAds%3Atrue

Once the scripts are loaded, you will have access to a number of AdsWizz related functions, one of which can be used to generate a listenerId and decorate a stream url with it. This ensure the listenerId is passed correctly to the stream url, without which we cannot poll for new metadata, or request advertisements.

Several aspects apply when connecting to an AdsWizz server instance that serves in-stream ad replacements (or pre-rolls).

  1. First the implementor must include the relevant AdsWizz Javascript snippets. This sets a cookie to track a listener id between listening sessions and includes other required functions.

  2. After this the stream URL(s) to be used must be "decorated" using functions inside the above loaded snippets. This essentially appends the listener ID to the URLs in an AdsWizz compatible manner.

  3. Finally the player is loaded, with ads enabled and providing the decorated stream URL(s) for playback. If the player needs to poll for companion banners additional configuration data is also required.

Configuration

Example: Configure AdsWizz

var player = new iono.Player({
    adswizz: {
        afrUrl: 'http(s)://<youradserver>.deliveryengine.adswizz.com/afr',
        interval: 5000,
        metadataUrl: 'http(s)://<streaming_server>:<live streaming port>/metadata',
        zoneAlias: 'DisplayZone'
    }
});

The AdsWizz features of the player may be configured using the adswizz option when initialising a player instance.

Option Type Default Description
afrUrl string null The AFR url used to load companion ads from an AdsWizz context received from the metadata url.
interval number 5000 Number of milliseconds to wait between metadata polling calls.
metadataUrl string null The metadata url used to poll for new metadata on an AIS stream.
zoneAlias `string\ string[]` DisplayZone

Metadata polling

By providing the metadatUrl option when creating a player instance, we enable the periodic polling of this url for new metadata. This url should be provided by your AdsWizz partner. This url will be polled every interval seconds, and any new entries encountered added to the timeline. Entries may include now playing data (such as the current song), or ad markers where ads start.

Companions ads

By providing both metadataUrl and afrUrl options when creating a player instance, we enable the display of companion ads on the ui. These urls should be provided by your AdsWizz partner and are used to watch for metadata updates on the content and to request companion ads. When a companion ad is started the player will emit the adcompanionstart event.

Zones

Your zones should be configurable on the AdsWizz platform. Using the zoneAlias option allows you to choose the zones to request from. Keep in mind that the zones you choose should serve companions with dimensions fitting those supported by our layouts. Currently our layouts support the following zone dimensions:

Layout 320x50 300x250
legacy yes no
square no yes

When the player is configured using the gdpr setting, the appropriate aw_0_req.gdpr and aw_0_req.userConsent parameters are added to the afrUrl to allow for user consent to be passed on to AdsWizz.

Appendix: Computed fields

Generic fields

Computed fields available at any point. This includes content source urls, ad source urls, ad request urls and custom analytics tracking urls.

Key Description Example
<cb> cachebuster 1621241075019
<version> player version number 1.0.0
<contentType> content type of the current playing content or ad podcast, ad-client
<uid> content id found in the playlist item metadata
<quality> current playback quality label high, medium, low
<format> current playback format mp3, m4a
<referer> page referrer https://example.com/path
<gdpr> whether GDPR shoudl be considered true, false
<userConsent> user consent string
<creator> the provider/publisher of the current content or ad Publisher name
<grouping> the artist/podcast or ad client of the current content or ad Podcast name
<muted> whether or not playback has been muted 0, 1
<playbackRate> current playback rate 1
<publishDate> publish date of the current content or ad as an ISO9601 string 2020-02-18T08:00:00.000Z
<title> the title of the current content or ad Podcast episode title
<volume> the current playback volume 0, 0.65, 1
<position> current content or ad playback position 10.45
<duration> current content or ad playback duration 30.56

Advertising fields

Computed fields only available while an advertisement is busy playing. This includes ad source urls, ad request urls and custom analytics tracking urls for ads that are playing.

Key Description Example
<adid> currently playing ad id
<adslot> the type of slot containing the current ad break pre, mid, post

Tracking fields

Computed fields only available on custom analytics tracking urls. This includes custom analytics tracking urls.

Key Description Example
<event> tracking event type start
<sid> player session id, updated every page request, unique per player instance 2faaab3a46d9d515b368d88995072f32
<uuid> unique user id, stored in localStorage 6f5b96bb3b0c8ecd2a7441b18b1af0c4
<percent> current tracking percentile 10, 25

Appendix: Syndicators

Syndication links are available to playlist and playlist item objects. These links allow us to render subscribe links on the player UI. Use the value from the "Service" column as your value for syndication.service.

Service Description
rss Url of an rss feed the user can subscribe to.
apple Apple Podacsts page the user can subscribe to.
google Google Podcasts page the user can subscribe to.
spotify Spotify page where the user can subscribe.
castbox Castbox page where the user can subscribe.
iheart iHeart Radio page where the user can subscribe.
playerfm PlayerFM page where the user cna subscribe.
podchaser Page on Podchaser where the user can subscribe.
stitcher Page on Stitcher where the user can subscribe.
soundcloud Page on SoundCloud where the user can subscribe.
amazon Amazon Music page where the user can subscribe.
deezer Deezer page where the user can subscribe.
listennotes Page on Listen Notes where the user can subscribe.
podcastaddict Podcast Addict page where the user can subscribe.
radiopublic Radiopublic page where the user can subscribe.
mixcloud Page on Mixcloud where the user can subscribe.
pocketcasts Page on Pocket Casts where the user can subscribe.
overcast Overcast page where the user can subscribe.

Appendix: "Now Playing" metadata

Live stream playback allows for retrieving and displaying metadata associated with the currently playing item, for example the song name and artist. This information must be retrieved via a side channel which the player polls continuously for updates.

Specifying "Now Playing" data for a stream

Example: stream playlist item that includes a "Now Playing" endpoint with dynamic values

{
    metadata: {
        contentType: 'stream',
        uid: 'example:stream:identifier:1',
        language: 'en',
    title: 'Example stream'
    },
    audio: [
        {
            url: 'https://example.com/stream.mp3',
            bitrate: 64000,
            quality: 'low',
        }
    ],
    links: [
        {
            kind: 'nowplaying',
            url: 'https://example.com/nowplaying/1?skip=<skip>&limit=<limit>',
        }               
    ]
}

To enable polling for metadata the stream playlist item must provide a nowplaying URL in the links metadata. If no URL is provided, the player will not poll for any current metadata.

To cater for displaying recent playback history, the player can use dynamic fields to perform pagination of now playing items. Specifying <limit> or <skip> in the URL allows the player to dynamically fill these fields as required:

The player will only poll for more than 1 items during initialisation. Subsequent requests while playback is active will always poll for the latest item only.

The nowPlayingInterval and nowPlayingMaxHistory configuration options can control the polling frequency and amount of historic items to retrieve.

Providing a server endpoint

The server endpoint that supplies now playing metadata must return one or more playlist item compatible JSON objects. The first object in the list must always be the item that is currently playing, with any additional items representing playback history from newest to oldest.

To enable efficient network use, the server endpoint should return a "Cache-Control" header with the content that allows the client to receive "HTTP 304 Not Modified" responses when polling for new data.

The server endpoint should never return more than 20 items in one request. The server endpoint should support receiving limit and skip parameters for providing paginated historic playback data.

Playlist item for "Now Playing"

Example: "Now Playing" metadata object

{
    v:1,
    metadata: {
        contentType: "stream",
    publishDate: "2019-04-16T17:54:51+02:00",
    title: "Thunderstruck",
    creator: "AC/DC",
    grouping: "Razor's Edge",
        duration: 293.0,
    }
}

There are no relevant standards for this metadata, so the player expects the data to conform to our playlist item structure. The contents are mapped as follows:

Name Required
v Required. Version of playlist item.
metadata Required. Metadata of the current playing item.
audio[] Omit.
text[] Omit.
links[] Omit.
tags[] Omit.
ads[] Omit.

The metadata object for each entry follows mostly the same rules as for normal playlists:

Name Type Description
contentType string Required. For now supports only stream.
publishDate string Required. Playback start time of item in ISO8601 format.
title string Required. Short title for the item. Should be the song or show name.
creator string Required. Creator of the content. Should be the artist or show presenter.
duration number Item duration in floating point seconds.
uid string Can contain any unique identifier, for example a song ISRC code. May be used for tracking and analytics.
url uri Online page with more detail about the content.
grouping string Grouping of content. Typically song album.
explicit bool Boolean that indicates if the content contains explicit language. Defaults to false.
icons[] array Up to 3 square images associated with this item, see image structure.

getNowPlayingItem

Example: returns the current "Now Playing" item

player.getNowPlayingItem();  // Get the current "Now Playing" item

Returns the newest "Now Playing" playlist item and false if no "Now Playing" data is available.

getNowPlayingHistory

player.getNowPlayingHistory(20);  // Get the last 20 "Now Playing" items, from newest to oldest

Returns the loaded "Now Playing" playlist items. The first parameter specifies the limit to return, defaults to returning the newest item only.

Returns false if no "Now Playing" data is available.

nowplayingchange

Example: new "Now Playing" data available

{
    type: 'nowplayingchange'
}

Fires after a new "Now Playing" playlist item has been received.

Appendix: Support functions

formatSeconds

Example: format seconds to an hh:mm:ss string

iono.Player.formatSeconds(0);     // 00:00
iono.Player.formatSeconds(30);    // 00:30
iono.Player.formatSeconds(60);    // 01:00
iono.Player.formatSeconds(90);    // 01:30
iono.Player.formatSeconds(3600)   // 1:00:00
iono.Player.formatSeconds(3690);  // 1:01:30

A static helper function that formats a number of seconds to an hh:mm:ss string.

Leading zeros on the hour value are removed, and the hour is only shown when the input is greater than or equal to an hour. Intended to be used for displaying current position and total duration of audio.

getUUID

Example: get current UUID

iono.Player.getUUID();

A static helper function that returns a unique user identifier.

The value is an SHA256 hash of random values, persisted between sessions via localStorage. Returns false on browsers without localStorage support available or enabled.

Example UUID string:

8dd80acd972e56d28badcc737bba616338dd76a1fea46ee015feaaaea1cae425

getSID

Example: get current SID

player = new iono.Player();
player.getSID();

An instance member that returns a unique session identifier.

A new SID is created for every instance of the player created, thus this function requires an instance of the player object.

It is also an SHA256 string similar to UUID.

Example SID string:

3be9728a988a5ea5d8eade0591d5954bf8acf1afeb9167441140cccf553f1065

getReferer

Example: get the current referer value

iono.Player.getReferer();

A static helper function that returns the current HTTP "Referer".

Because the player is frequently used inside an iframe object, this function wraps logic that gets "Referer" from the parent window when it has been instantiated inside an iframe. This is typically the expected behaviour, eg: a customer would want to see the location of the iframe, not it's own URL.

getEnvironment

Example: get the current player environment variables

iono.Player.getEnvironment();

Returns the current player environment.

Note that the network field is only available on devices that supports the NetworkInformation API.

{
  "isIframe": false,
  "isMobile": false,
  "browser": {
    "name": "chrome",
    "version": {
      "major": 71,
      "minor": 0
    },
    "isIE": false,
    "isEdge": false,
    "isOpera": false,
    "isChrome": true,
    "isSafari": false,
    "isFirefox": false,
    "isAndroidNative": false
  },
  "platform": {
    "name": "mac",
    "version": {
      "major": 10,
      "minor": 14
    },
    "isAndroid": false,
    "isWindows": false,
    "isIOS": false,
    "isMacintosh": true
  },
  "network": {
    "isAvailable": true,
    "effectiveType": "4g",
    "downlink": 10,
    "downlinkMax": 10,
    "rtt": 250
  }
}

Appendix: Audio MIME types

Audio track MIME types are use to determine playback compatibility on the current browser.

When loading direct URL's the player will also use this list to map from extension to MIME type.

Extension MIME Description
m3u8 application/x-mpegURL HLS playlist pointing to TS fragments.
ts video/mp2t TS fragment containing AAC audio data.
aac audio/aac AAC audio, typically used for live-streaming without MP4 encapsulation.
m4a,mp4 audio/mp4 AAC audio, embedded inside an MP4 container. May also be audio/x-m4a.
mp3 audio/mp3 MP3 file or stream in it's native container format.
oga,ogg audio/ogg Vorbis audio stream in Ogg container format.
webm audio/webm; codecs="vorbis" Vorbis audio stream inside WebM container format.
opus audio/ogg; codecs="opus" Opus audio stream in Ogg container format. May also be audio/opus when not encapsulated in Ogg container format.
wav audio/wav PCM Waveform audio.

For audio/aac, audio/m4a or audio/m4a the specific AAC profile used should be indicated:

Profile MIME string Description
aac-lc codecs="mp4a.40.2" AAC Low Complexity, the most common format, suitable for most bitrates.
aac-he codecs="mp4a.40.5" AAC High Efficiency v1, suitable for bitrates up to 64k.
aac-he2 codecs="mp4a.40.29" AAC High Efficiency v2, suitable for bitrates up to 48k.

Other profiles exists and may be supported in the future.

Appendix: Player examples

Stream player

Example: stream player

<html>
<head>

    <title>Example: Stream Player</title>

    <!-- Import Bootstrap for basic styling -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin>

    <!— Support HLS stream playback —>
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest" crossorigin></script>

    <!— Load the latest iono.fm player bundle -->
    <script src="https://p2.iono.fm/bundle/0.2.1/player.js" crossorigin></script>

</head>
<body>
    <div class="container">
        <div class="d-flex align-items-center py-3">

            <!-- Toggle playback button -->
            <button id="toggle-play" type="button" class="btn btn-primary">Play</button>

            <!-- Show current position -->
            <span class="px-3" id="position">00:00</span>

            <div class="d-inline-flex align-items-center">

                <!-- Toggle mute button -->
                <button id="toggle-mute" type="button" class="btn mr-2 btn-sm btn-secondary">Mute</button>

            </div>
        </div>

        <!-- Event debugging -->
        <h6 class="text-muted">Tracking events:</h6>
        <pre class="pre-scrollable"><code id="console"></code></pre>
    </div>

<!-- Player init and bindings -->
<script>
    var player;
    var $console;

    // Helper function to format seconds to hh:mm:ss
    function formatSeconds(seconds) {
        var ss = Math.max(0, parseInt(seconds, 10));
        var hh = Math.floor(ss / 3600);

        ss -= (hh * 3600);

        var mm = Math.floor(ss / 60);

        ss -= (mm * 60);

        mm = ('00' + mm).substr(-2);
        ss = ('00' + ss).substr(-2);

        if (hh > 0) {
            return hh + ':' + mm + ':' + ss;
        }

        return mm + ':' + ss;
    }

    // Because of the "defer" attribute on our scripts, we have to wait from DOM to load completely before we can initialise a player instance
    window.addEventListener("DOMContentLoaded", function(event) { 
        // Cache DOM elements
        $console = document.getElementById('console');

        // Instantiate player object
        player = new iono.Player(document.getElementById('player'));

        // When player object is ready, attach relevent actions
        player.ready(function () {
            // Assume a button on the page named 'toggle-play' will start/stop playback
            const $togglePlay = document.getElementById('toggle-play');

            // Toggle playback when the button is clicked
            $togglePlay.addEventListener('click', function () {
                player.togglePlay();
            });

            // Update the toggle button text depending on the paused state
            player.on('play', function () {
                $togglePlay.textContent = 'Pause';
            });
            player.on('pause', function () {
                $togglePlay.textContent = 'Play';
            });

            // Assume a button on the page name 'toggle-mute' will mute/unmute volume
            const $toggleMute = document.getElementById('toggle-mute');

            // Toggle volume mute when the button is clicked
            $toggleMute.addEventListener('click', function () {
                player.toggleMute();
            });

            // Asume a label on the page named 'position' will display the playback position
            const $position = document.getElementById('position');

            // Update the position on the ui when the current playback position changes
            player.on('timeupdate', function (event) {
                // use the formatSeconds utility to convert the position
                // from seconds to an hh:mm:ss timecode
                $position.textContent = formatSeconds(event.position);
            });

            // Update the label of the mute button when volume changes
            player.on('volumechange', function (event) {
                $toggleMute.textContent = player.getMute() ? 'Unmute' : 'Mute';
            });

            // Debug tracking events
            player.on('tracking', function (event) {
                // action tracking events
                if (event.details.event === 'action') {
                    $console.textContent += ('TrackingEvent(action): ' + event.details.action + '\n');
                }
                // position tracking events
                if (event.details.event === 'position') {
                    $console.textContent += ('TrackingEvent(position): ' + event.details.position + '\n');
                }
            });

             // Load the stream URL
            player.load('https://example.com/stream.m3u8');
        });
    });    
    </script>
</body>
</html>

This is an example of a basic stream player.

Some highlights from this example:

To test this example, simply save the contents to a file and serve from an HTTP enabled web-server. Some browsers like Chrome also allows opening it from a local saved file.

The example uses a hardcoded direct stream URL which can be changed to another URL or extended to use a more complete JSON playlist item.

Stream with client-side ad

This example shows how to load and play ads served by an ad server. This includes displaying companion ads.

Example: HTML code

<div id="contentState">
    <button id="playPauseButton">Play</button>
</div>

<div id="advertState" hidden>
    <div id="adCompanionContainer"></div>
</div>

<!-- load the hls.js library for HLS support on supported browsers -->
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="https://p2.iono.fm/bundle/0.2.1/player.js"></script>

Example: CSS code

#adCompanionContainer {
  width: 300px;
  height: 250px;
}

Example: JavaScript code

var $adCompanionContainer = document.querySelector('#adCompanionContainer');
var $playPauseButton = document.querySelector('#playPauseButton');
var $contentState = document.querySelector('#contentState');
var $advertState = document.querySelector('#advertState');

// toggle playback when the play/pause button is clicked
$playPauseButton.addEventListener('click', function() {
    player.togglePlay();
});

var player = new iono.Player({
    // a license that allows advertisements is required for the ad features to function
    license: 'iono-test-key',
    ads: {
        // ads must also be enabled on the player instance
        enabled: true
    }
});

player.on('play', function(event) {
    $playPauseButton.textContent = 'Pause';
});

player.on('pause', function(event) {
    $playPauseButton.textContent = 'Play';
});

player.on('stop', function(event) {
    $playPauseButton.textContent = 'Play';
});

player.on('adstart', function(event) {
    $contentState.setAttribute('hidden', true);
    $advertState.removeAttribute('hidden');
});

player.on('adend', function(event) {
    $contentState.removeAttribute('hidden');
    $advertState.setAttribute('hidden', true);
});

var currentCompanion;
player.on('adcompanionstart', function(event) {
    // this event fires for all companions on the ad object, the ui should choose
    // the correct one to display by comparing the creative dimensions with the
    // dimensions of the companion ad slot in the ui
    if (
        (event.companion.width > $adCompanionContainer.clientWidth) ||
        (event.companion.height > $adCompanionContainer.clientHeight)
    ) {
        return;
    }

    // update the current companion so that we can hide it later when it ends
    currentCompanion = event.companion;

    // update the companion ad, using an iframe here as an example, but could set 
    // the background image or the src of an <img>
    $adCompanionContainer.innerHTML = '<iframe src="'+ event.companion.url +'" width="100%" height="100%" frameborder="no"></iframe>';
});

player.on('adcompanionend', function(event) {
    // check that the current companion matches the one that just ended
    // and hide the companion ad
    if (currentCompanion && currentCompanion.url === event.companion.url) {
        $adCompanionContainer.innerHTML = '';
        currentCompanion = null;
    }
});

// load the iono test stream in to the player
player.load({
    metadata: {
        contentType: 'stream',
        uid: 'stream:1',
        duration: 0
    },
    audio: [
        {
            url: 'https://example.com/stream.mp3',
            bitrate: 80000,
            quality: 'medium',
            mime: 'audio/mp3'
        }
    ],
    ads: [
        {
            position: 0,
            metadata: {
                contentType: 'ad-client'
            }
        }
    ]
});

Loading a new source in to the player

Example: loading a new source after one has already been loaded

// load the first source
player.load(audio_source_1);
player.play();

// later, load the second source, this stops the current playback and loads the new source
player.load(audio_source_2);
player.play();

Setting hls.js configuration options

The hlsjs config option takes an object matching the structure documented by the hls.js library. The hls.js library must be loaded on the page before the player is able to load hls streams on browsers that don't natively support HLS playback.

Example: allowing cookies to be sent with hls requests (required when requesting hls files from third-parties)

const player = new iono.Player({
  hlsjs: {
    xhrSetup: function(xhr, url) {
      xhr.withCredentials = true;
    }
  }
});