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:
- playback of both podcast and live-stream audio,
- support for multiple codecs and formats with codec auto-selection,
- support for multiple quality levels with user-driven selection available,
- tracking of server-side ads pre-inserted (stitched) into the audio stream,
- delivery of client-side ads in pre-, mid- and post-roll positions,
- analytics tracking events for ad delivery and listener behaviour.
Some additional features are highly desirable:
- easily load and manage a playlist of items,
- support for chapter markers and captions.
- load a playlist from an iTunes-compatible RSS feed,
Supported formats
The player aims to supports the following audio formats:
Podcasts:
- AAC, MP3, WebM and Opus files
- HTTP Live Streaming (HLS) with AAC or MP3 contents (via hls.js)
Live streams:
- Icecast over HTTP with AAC or MP3 contents
- HTTP Live Streaming (HLS) with AAC or MP3 contents (via hls.js)
Text tracks:
- WebVTT compatible files with caption or chapter data
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. |
Links
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:
Client side (
ad-client) : ads that must be loaded and played by the player. The player will populate their structure content after loading from the ad server.Server side (
ad-server) : ads that are already inserted into the audio file or stream by the server. Defining these allows the player to trigger metadata events and send tracking analytics during ad playback. These ads do not specify anyaudiotracks as the ad forms parts part of content audio track.
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:
- Direct audio file URL. Creates a playlist item, populating some metadata from the URL structure.
- Playlist URL. Loads a compatible JSON playlist from a remote URL.
- Playlist object. A valid playlist object passed directly in Javascript.
- 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:
- If no index is specified, the current playlist item is returned.
- If an integer is specified, the item at that index is returned, if any.
- If a string is specified, the item with the associated UID is returned, if any.
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:
-1if the current audio source is a live stream.-2if position is outside the boundaries of the known duration.-3if there is no item loaded.
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):
Chapters: Available chapter markers for the audio. These typically consist of a short title and a position range in the audio.
Subtitles: Text cues to be displayed alongside audio playback that provides a text representation of speech inside the audio. This should be used when providing transcripts of audio content.
Captions: Text cues that can be provided to describe environmental effects in the audio using text. Some examples "People laughing" or "Cars passing by".
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:
- iono.fm client side ads - complete client side model, where the player requests ads from the iono.fm platform. Ads may include companion banner data.
- iono.fm embedded podcast ads - the player detects ads embedded inside podcasts files. Ads may include companion banner data.
- AdsWizz in-stream ads - the player detects in-stream ads served by the server and attempts to get companion data from the the AdsWizz server.
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:
- the
uidfield, whose value should be the unique identifer for the current loaded playlist item. - the full
adstructure, see example from Advertising section.
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
readystate 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:
- Action tracking events are driven by user interaction,
- 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:
- Sections of audio was skipped,
- Playback speed was increased,
- Volume was muted or turned to 0
Action events
The list of action tracking events that fire is defined by typical tracking use cases:
play: the user started playbackpause: the user paused playbackdownload: the user triggered the download functionalityresume: the user resumed playback after pausingmute: the user activated the mute controlunmute: the user deactivated the mute controlrewind: the user skipped backwards in the audio contentskip: the user skipped forward in the audio content
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:
- source URL when loading playlist,
- source URL when specified inside a playlist,
- custom analytics tracking URL
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.urlconfigured 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:
- All event field data will encoded as URL parameters and sent via
HTTP GETrequests. - The URL should leverage the cache-busting field (
cb) to prevent browser caching.
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:
- Must be able to decode any text values from their URL encoded values,
- Must return the Access-Control-Allow-Origin: * header to errors inside the browser,
- Should be available via HTTPS,
- Should return the HTTP 200 OK or HTTP 202 Accepted status codes,
- Should return the Cache-Control: no-cache header to prevent the browser from caching requests
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:
- Pre-create waveform data using version 2 of the BBC Audio waveform library in pixel-per-second resolution.
- Provide a link to this file in the
waveformentry of the playlistlinkssection. - The waveform can be provided as JSON format or the smaller binary format with a
.datextension. - When using waveforms version 2 of the BBC
waveform-data.jslibrary must be loaded.
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:
- A JSON playlist URL is loaded,
- The playlist URL includes the
<skip>and<limit>options.
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.
Search
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).
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.
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.
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 |
GDPR and user consent
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:
<limit>: Limit the number of items returned. Default from server if not specified should be1.<skip>: Skip over number of items, used for pagination. Default from server if not specified should be0.
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:ssstring
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:
- Uses the "latest" build of the player (not recommended for production use),
- Loads hls.js to play an HLS stream,
- Binds to several events to show basic UI functionality like toggling play/pause and showing elapsed time.
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;
}
}
});