AV Reporting
Table of contents
- Set Media player attributes
- Media Player Volume
- Instantiating the Media class
- Setting Media Theme Information
- Pass the Media object to EchoClient
- Media Events
- Buffering
- Handling buffering after a seek event
- Buffering Example
- The Player Delegate
- Window State
Set Media player attributes
First tell Echo about your player name, version, volume etc.
echo.setPlayerName('MyMediaPlayer')
.setPlayerVersion('0.1.0')
.setPlayerVolume(30);
echo.setPlayerName("MyMediaPlayer");
echo.setPlayerVersion("0.1.0");
echo.setPlayerVolume(30);
echo.setPlayerName("MyMediaPlayer")
echo.setPlayerVersion("0.1.0")
echo.setPlayerVolume(30)
Media Player Volume
Echo’s media player volume range is from 0-100, where 0 being the lowest volume and 100 being the highest. If you need to perform a calculation to match this range (for example, if your volume goes up to 11) then please use floor and not round.
Instantiating the Media class
Before you can send AV events, meta-data about the media content must be set. This is passed to your instance of EchoClient
using an instance of the Media
class:
You should aim to provide Echo with meaningful content IDs:
- a version ID for on-demand or download
- a service ID for a live simulcast
- a version ID for a live webcast
If you don’t have these then it is possible supply a lesser ID as shown below, but only one is required and it is not necessary to provide additional identifiers (they will be discarded).
The setVpid
method should only be used when you are unable to determine if an identifier represents a service or version (eg SMP playlist item vpid).
For more information about setting media producer, including how to use a string or masterbrand string, see the Reporting to Piano page here.
var myPieceOfMedia = new Media(
Enums.AvType.VIDEO, // Type (Video or Audio)
Enums.MediaConsumptionMode.LIVE, // On demand / Download / Live
);
// Set the media producer
myPieceOfMedia.setProducer(Enums.Producer.BBC_THREE);
// Set at least one of the required ids
myPieceOfMedia.setVersionId("some_valid_versionId");
myPieceOfMedia.setServiceId("some_valid_serviceId");
myPieceOfMedia.setEpisodeId("some_valid_episodeId");
myPieceOfMedia.setClipId("some_valid_clipId");
// only use setVpid if you do not know an explicit version or service Id
// eg an SMP playlistObject.item.vpid
myPieceOfMedia.setVpId("some_valid_vpId");
// set length (in ms) if you know it
// you do not need to set length for 'live' media
myPieceOfMedia.setLength(3600000);
// COMING SOON: set media language if you know it
myPieceOfMedia.setLanguage("en-gb"); // Not yet available on JS
Media myPieceOfMedia = new Media(
MediaAvType.VIDEO,
MediaConsumptionMode.LIVE);
// Set the media producer
myPieceOfMedia.setProducer(Producer.BBC_THREE);
// Set at least one of the required ids
myPieceOfMedia.setVersionId("some_valid_versionId");
myPieceOfMedia.setServiceId("some_valid_serviceId");
myPieceOfMedia.setEpisodeId("some_valid_episodeId");
myPieceOfMedia.setClipId("some_valid_clipId");
// only use setVpid if you do not know an explicit version or service Id
// eg an SMP playlistObject.item.vpid
myPieceOfMedia.setVpId("some_valid_vpId");
// set length (in ms) if you know it
// you do not need to set length for 'live' media
myPieceOfMedia.setLength(3600000);
// set media language if you know it
myPieceOfMedia.setLanguage("en-gb");
media = Media(avType: .video, consumptionMode: .onDemand)
// Set the media producer
media.producer = .BBCThree
// Set at least one of the required ids
media.versionID = "some_valid_versionId"
media.serviceId = "some_valid_serviceId"
media.episodeId = "some_valid_episodeId"
media.clipId = "some_valid_clipId"
// only use setVpid if you do not know an explicit version or service Id
// eg an SMP playlistObject.item.vpid
media.vpId = "some_valid_vpId"
// set length (in ms) if you know it
// you do not need to set length for 'live' media
media.length = 3600000
// set media language if you know it
media.language = "en-gb"
Setting Media Theme Information
Additional information (see table below) about the media object can be set by the appropriate methods. This information is applied to the media theme attribute for reporting purposes.
For more information on Media Themes see this Confluence page
Property | Function | Example | Description |
---|---|---|---|
Name |
| six nations special | The asset title. |
Playlist |
| sounds of the 70s | The name/identifier of the playlist. For a live stream this is automatically set to the Service ID. |
World Service Partner ID |
| news.mail.ru | The partner identifier is used to define content playback for a syndication partner. |
Media Player Name |
| smphtml5 | The name of the media player playing the content. |
Media Player Version |
| 2.21.23.5 | The version of the media player playing the content. |
Casting device referrer |
| cc | The device referrer value is the referring device for casting devices:
|
Pass the Media object to EchoClient
Once you have created a Media object you must pass it to the EchoClient’s setMedia
medthod.
Media
object after you have passed it to EchoClient.setMedia()
will be ignored by Echo. You must use methods on the EchoClient
eg EchoClient.setMediaLength()
to inform Echo about changes to media length. Length can only be set once, subsequent changes will be ignored by ATI. echo.setMedia(myPieceOfMedia);
/**
* When you know the media length you should call the appropriate Echo Client method.
*
* Any changes made to a media object after it has been passed to
* setMedia will be ignored.
*/
// you do not need to set the length for 'live' media
// the length value will default to 0
// you can also set it to 0 if desired
echo.setMediaLength(50000); // NB in ms
echo.setMedia(myPieceOfMedia);
/**
* When you know the media length you should call the appropriate Echo Client method.
*
* Any changes made to a media object after it has been passed to
* setMedia will be ignored.
*/
// you do not need to set the length for 'live' media
// the length value will default to 0
// you can also set it to 0 if desired
echo.setMediaLength(50000);
echo.setMedia(myPieceOfMedia)
/**
* When you know the media length you should call the appropriate Echo Client method.
*
* Any changes made to a media object after it has been passed to
* setMedia will be ignored.
*/
// you do not need to set the length for 'live' media
// the length value will default to 0
// you can also set it to 0 if desired
echo.setMediaLength(50000)
Media Events
After calling echo.setMedia()
you can begin sending AV measurements. Each method requires the media playhead position to be passed in, and also accepts a properties object:
avPlayEvent
should not be called when the user activates the play button, but when you start the media actually begins playing. You should wait until any calls to mediaselector etc have completed. avEndEvent
should only be called when playback of a media item can no longer continue eg you are exiting a screen with a player, a player is about to play a different item. If you have reached the end of a stream and the user is still able to rewind and continue playback you should use an avPauseEvent
. avPauseEvent
or avEndEvent
as instructed above. - do not need to specify a length
- should provide 0 as the position for avPlayEvent, avPauseEvent etc
// Start playing the media
echo.avPlayEvent(0);
// Pause (passing an optional custom property for this event)
echo.avPauseEvent(5000, {prop : 'custard'});
// Start playing again
echo.avPlayEvent(5000);
// Starts to buffer
echo.avBufferEvent(5100);
// Resumes again
echo.avPlayEvent(5100);
/**
* avSeekEvent, avRewindEvent and avFastForwardEvent will put Echo
* into a paused state. You must call avPlayEvent in order to
* resume playback.
*/
// Seek (position represents position prior to seek)
echo.avSeekEvent(12000);
echo.avPlayEvent(10000);
// Rewind (position represents position prior to rewind)
echo.avRewindEvent(11000,2);
echo.avPlayEvent(10000);
// Fastforward (position represents position prior to fast-forward)
echo.avFastForwardEvent(6000,2);
echo.avPlayEvent(10000);
/**
* Call avEndEvent when the current media item can longer be resumed.
* Once this event is called you will not be able to call
* any other av events eg avPlayEvent against the current media
* item.
*/
echo.avEndEvent(20000);
// Start playing the media
echo.avPlayEvent(0);
HashMap<String, String> pauseProps = new HashMap<String, String>();
pauseProps.put("lablab", "custard");
// Pause (passing an optional custom property for this event)
echo.avPauseEvent(5000, pauseProps);
// Start playing again
echo.avPlayEvent(5000);
// Starts to buffer
echo.avBufferEvent(5100);
// Resumes again
echo.avPlayEvent(5100);
/**
* avSeekEvent, avRewindEvent and avFastForwardEvent will put Echo
* into a paused state. You must call avPlayEvent in order to
* resume playback.
*/
// Seek (position represents position prior to seek)
echo.avSeekEvent(2000);
echo.avPlayEvent(2000);
// Rewind (position represents position prior to rewind)
echo.avRewindEvent(10000, 4);
echo.avPlayEvent(5000);
// Fastforward (position represents position prior to fast-forward)
echo.avFastForwardEvent(6000, 2);
echo.avPlayEvent(10000);
/**
* Call avEndEvent when the current media item can longer be resumed.
* Once this event is called you will not be able to call
* any other av events eg avPlayEvent against the current media
* item.
*/
echo.avEndEvent(10000);
// Start playing the media
echo.avPlayEvent(at: 0, eventLabels: nil]
// Pause
echo.avPauseEvent(at: 5000, eventLabels: nil)
// Start playing again
echo.avPlayEvent(at: 5000, eventLabels: nil)
// Starts to buffer
echo.avBufferEvent(at: 5100, eventLabels: nil)
// Resumes again
echo.avPlayEvent(at: 5100, eventLabels: nil)
/**
* avSeekEvent, avRewindEvent and avFastForwardEvent will put Echo
* into a paused state. You must call avPlayEvent in order to
* resume playback.
*/
// Seek (position represents position prior to seek)
echo.avSeekEvent(at: 5000, eventLabels: nil)
echo.avPlayEvent(at: 2000, eventLabels: nil)
// Rewind (position represents position prior to rewind)
echo.avRewindEvent(at: 10000, rate: 1, eventLabels: nil)
echo.avPlayEvent(at: 5000, eventLabels: nil)
// Fastforward (position represents position prior to fast-forward)
echo.avFastForwardEvent(at: 6000, rate: 1, eventLabels: nil)
echo.avPlayEvent(at: 10000, eventLabels: nil)
/**
* Call avEndEvent when the current media item can longer be resumed.
* Once this event is called you will not be able to call
* any other av events eg avPlayEvent against the current media
* item.
*/
echo.avEndEvent(at: 10000, eventLabels: nil)
Buffering
Please follow these rules when reporting buffering to Echo:
- You should notify Echo that buffering has started using the
avBufferEvent
method when you expect content to be playing but the media is no longer progressing. (so not, for example, when loading media after pressing the play button for the first time.) - You should not notify Echo that buffering has started before the media has started playing. Echo will ignore it if you do.
- If you enter an error state/screen following a period of buffering then notify Echo of a pause or end event. Time spent on an error screen should not count as playing or buffering time.
It is important that you inform Echo when you enter a non-playing, non-buffering state eg an error screen as this should not count as playing or buffering time. See the examples and screenshots below. Failure to correctly report changes to playing state will result in inaccurate values being reported and distorted overall playing/buffering time reporting.
Handling buffering after a seek event
When you seek within an AV item some degree of buffering is expected. This should not be reported to Echo as buffering is an expected interuption to playback.
Depending on how your player or application is implemented a number of outcomes may follow a seek:
- seek completes succesfully after a short time and playback continues (do not report buffering to Echo)
- seek fails so you are unable to continue playback (do not report buffering to Echo)
- enters a buffering state after a period of time has passed (you may want to report buffering to Echo)
Buffering Example
1) Content is playing
Call EchoClient.avPlayEvent(0);
2) Playback stops progressing due to buffering
Playback progress has stopped. Some sort of buffering indicator may be displayed.
Call EchoClient.avBufferEvent(120000);
3) Buffering ends and an error screen is displayed
After some time spent in a buffering state that player has decided to display an error message to the user. The player is no longer in a buffering state.
Call EchoClient.avPauseEvent(120000);
If buffering ends and you are able to continue playback you should call the avPlayEvent
method.
The Player Delegate
In addition to player position values being passed into Echo methods such as avPlayEvent
Echo must also also be able to pull position or timestamp values from players. This is achieved by players implementing the Echo PlayerDelegate interface with the following methods:
Method | Consumption Mode | Value | Frequency | Notes |
---|---|---|---|---|
getPosition | on-demand or download | 0 or position in milliseconds | 200ms | Only called if BARB is enabled. |
getTimestamp | live | 0 or epoch in milliseconds | 1 second | Used for both ATI and BARB |
If you are unable to provide a value you can safely return 0 whenever either method is called.
For more detail on the workings of the BARB Spring library see the Spring library documentation.
Note that although ATI does not report the actual position of the media, this information is still used for other purposes within Echo, for example ESS live media metadata enrichment
Timestamps
Echo expects players to provide a value representing the broadcast time for the content currently being consumed as an offset since 1 January 1970 00:00:00 UTC in milliseconds eg 1464702095000 which represents Tue, 31 May 2016 13:41:35 GMT.
It is expected that this will be obtained from the metadata available through the stream being consumed (you may need to convert to milliseconds). If you know that your timestamp does not include leap seconds please correct for this before passing a value to Echo.
NSTimeInterval
type, which specifies a value in seconds (as opposed to the milliseconds used by other platforms). The above example would therefore be given as 1464702095.000
. Example
/**
* Assumes some object called player with a position and timestamp
* property exists in your application.
*
* Your implementation will vary.
*/
var playerDelegate = {
getPosition: function() {
return player.position;
},
getTimestamp: function() {
return player.timestamp;
}
};
// create an EchoClient instance
var echo = new EchoClient('MyApp', Enums.ApplicationType.WEB);
// pass in a reference to you player delegate implementation
echo.setPlayerDelegate(playerDelegate);
// create a piece of media
var media = new Media(Enums.AvType.VIDEO, Enums.MediaConsumptionMode.LIVE);
media.setServiceId('bbc_one_london');
echo.setMedia(media);
// start playing
echo.avPlayEvent(0);
// Echo will start calling playerDelegate.getTimestamp once a second
import uk.co.bbc.echo.interfaces.PlayerDelegate;
import uk.co.bbc.echo.EchoConfigKeys;
public class MediaDelegate implements PlayerDelegate {
private long position;
private long timestamp;
private void updatePosition() {
//....Implement update behaviour
}
private void updateTimestamp() {
//....Implement update behaviour
}
public long getPosition() {
this.updatePosition();
// Return position of
return this.position;
}
public long getTimestamp() {
this.updateTimestamp();
// Return epoch timestamp
return timestamp;
}
}
// In your app
public class TestShellApplication extends Application {
private MediaDelegate mediaDelegate;
public long initApplication() {
HashMap<String, String> config = new HashMap<String, String>();
config.put(EchoConfigKeys.USE_ESS, true);
mediaDelegate = new MediaDelegate();
EchoClient echo = new EchoClient(
"MyApp", // App Name
ApplicationType.MOBILE_APP, // App type
"echo.android.test", // App Countername
getApplicationContext(), // The Android Context of your Application
config, // config options HashMap
bbcUser, // BBCUser instance
this // Application instance of your Application
);
// Android also requires these player attributes to be set
echo.setPlayerName("Some Player");
echo.setPlayerVersion("1.0.1");
echo.setPlayerSize(400, 600);
echo.setPlayerDelegate(mediaDelegate);
}
}
import Echo
class MediaDelegate: PlayerDelegate {
var position: UInt64?
var timestamp: TimeInterval?
func updatePosition() {
//....Implement update behaviour
}
func updateTimestamp() {
//....Implement update behaviour
}
func getPosition() -> UInt64 {
updatePosition()
return this.position
}
func getTimestamp() -> TimeInterval {
this.updateTimestamp()
return timestamp
}
}
// In your app
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//Echo Config
var config:Dictionary<EchoConfigKey, String> = [
.echoTrace: "echo_demo_ios",
// other config values here
]
// BBCUser
user = BBCUser(signedIn: true,
hashedID: hashedId,
tokenRefreshTimestamp: Date(timeIntervalSince1970: 1510156737)
)
mediaDelegate = MediaDelegate()
// Initialise Echo
do {
echo = try EchoClient(appName: "EchoDemoApp",
appType: .mobileApp,
startCounterName: "bbc.start.page",
config: config,
bbcUser: user)
} catch {
// Handle Echo config error
}
// Set player attributes
echo.setPlayerName("Some Player")
echo.setPlayerVersion("1.0.1")
echo.setPlayerSize(400, 600)
echo.setPlayerDelegate(playerDelegate: mediaDelegate)
return true
}
Window State
Set the player window state mode.
Modes | JS | Android | Swift | |
---|---|---|---|---|
Normal | NORMAL | NORMAL | .normal | |
Full | FULL | FULL | .full | FULL |
Minimised | MINIMISED | MINIMISED | .minimised | |
Maximised | MAXIMISED | MAXIMISED | .maximised | |
Resized | - | RESIZED | .resized | |
Picture in picture | PICTUREINPICTURE | PICTUREINPICTURE | .pip |
echo.setPlayerWindowState(Echo.WindowState.FULL);
echo.setPlayerWindowState(WindowState.FULL)
echo.setPlayerWindowState(.full)