Version | 2.3 |
---|---|
Date | 11.11.2019 |
Author | Kantar Media Division |
Version history
Version | Date | Author | Comments |
---|---|---|---|
0.1 | 23.05.2005 | Christopher Wirtz | Initial |
0.5 | 26.05.2005 | Christopher Wirtz | Changes |
1.0 | 02.06.2005 | Christopher Wirtz | Release |
1.1 | 12.03.2007 | Christopher Wirtz | Flash added |
1.2 | 06.07.2009 | Christopher Wirtz | Review/Changes |
1.3 | 14.07.2009 | Christopher Wirtz | Added Example to set the „duration“ manually in ActionScript |
1.4 | 29.06.2010 | Christopher Wirtz | Unload Delay |
1.5 | 02.11.2010 | Frank Kammann | Add Example using a NetStreamAdapter, Streaming Segments and parallel Streams |
1.6 | 14.03.2011 | Frank Kammann | Description of the general Operation (API) and Information on the Security Settings for Flash |
1.7 | 17.09.2012 23.10.2012 | Christopher Wirtz Ralf Cornehl | Adapting the position-based Stream Measurement to event-based Measurement Review, Adapting Explanations |
1.8 | 04.12.2012 04.12.2012 | Frank Kammann Ralf Cornehl | Mobile Streaming added Review, Adapting Explanations, Translation into English |
1.9 | 13.05.2013 13.05.2013 26.09.2013 | Frank Kammann Katrin Joachimsky Ralf Cornehl | Chapter HTML5 added Translation into English Adapting Stream Name Guidelines |
2.0 | 22.01.2014 10.11.2014 19.08.2015 | Hendrik Vermeylen Ralf Cornehl Ralf Cornehl | Offline Mode for App Streaming Opt-Out Method URL-scheme added for iOS |
2.1 | 25.09.2015 | Ralf Cornehl | iOS9 Support (URL-Scheme-White-listing, ATS, Bitcode) |
2.2 | 18.10.2017 | Marc Born | Android Streaming Sensor now uses Singleton template for creation |
2.3 | 11.11.2019 | Christopher Kirch | Implementation Streaming for Cordova |
Whether news shows, product presentations or online radio programs - all are now using audio and video streams as medium of communication.
Even more than on the static pages, not only the number of visitors but also the behavior of users within a stream is of interest. For how long the clip was actually viewed, which sections were of particular interest and which were not?
When streaming media is called from a web site that is composed by the COM model and/or Flash, it is not only possible to track the number of users, but also watching the users’ behavior.
This document describes the integration of streaming measurement for different applications.
In order to measure any streaming content, a sensor on the client side is necessary, which measures which sequences of the stream were played by the user.
These sequences can be defined by time intervals in seconds - therefore, the player or the playing instance must be able to provide a method for delivering the actual position on the stream in seconds.
The regular reading of the current position allows the tracking of all actions on a stream. Winding operations can be identified, if there are unexpected jumps in reading out the position. Stop or pause operations are identified by the fact, that the current position will not change.
User actions and operations like stop or pause are not measured directly (not player event based) but are instead derived from measuring the current position on stream.
The following chart shows the architecture of the API:
The simplicity of the API and the concept lead to the following features:
|
The following discussion is presented in JavaScript syntax. The procedure is more or less the same in any programming language used.
// 1. Instantiate the API object var sensors = new SpringStreams("site code"); // 2. Create a description object for streaming content var desc = { "stream":"videos/mystream", "duration":600, // in seconds "sx":video.width, "sy":video.height }; // 3. Provide a content object var content = ...; // Any object, which is able to deliver the current position on the stream in seconds // 4. Register the content with the description object on the sensor var stream = sensors.track(content, desc); |
Remarks:
to 1: Instantiate the API object
The correct site code must be setup. The site code is delivered by the owner of the streaming solution.
var sensors = new SpringStreams("site code"); |
SpringStreams
has to be setup once on the framework. From there, one or more streams can be transmitted to the measurement by the track
method.to 2: Create a description object for streaming content
In the description object, at least the name of the stream must be given
var desc = { "stream":"videos/mystream", "duration":600 // in seconds }; |
Variable | Optional | Description | |
---|---|---|---|
| No | Name of the stream, which is ideally given as a hierarchy. Example: In general there is no limitation of the charset – conform to the JSON standard http://json.org – , but for having a better interpretation of stream paths in scores we advice to use the described standards below. The allowable character set for all values in the tagging is UTF-8. It is however recommended to limit to the following characters:
| |
| Yes | The duration must be setup if there's no adapter implementation. | |
| Yes | Any value, that makes a statement about the content type can be used | |
cq | Yes | Any value, that makes a statement about the content quality can be used For example, the value "programme-ID" can be given to the stream to mark it as an unique content | |
| Yes | The width of the stream window - if it's a movie | |
| Yes | The height of the stream window - if it's a movie |
to 3: Provide a content object
The only requirement of the streaming API for this object is delivering the current position on a stream in seconds. Depending on the programming language used certain technical software solutions are possible, such as the implementation of interfaces or the implementation of adapter classes.
var content = ...; |
to 4: Register the content with the description object on the sensor
track
. From this point on the current position on the stream is tracked. At this point it's possible to measure several parallel streams, where each additional streaming content with the accompanying description object is given to the track
method.var stream = sensors.track(content, desc); |
Stream.stop()
.After the streaming content with the accompanying description object has been passed to the track
method, the current position on the streaming content is queried every 200ms. Internally, all intervals are collected, which were viewed by the user on the stream. At a constant viewing this is one interval.
Once it's determined that the current position changes by more than 1 second to the expected position a start, stop or winding event or even a buffering phase can be assumed. In this case, a new interval is created.
An interval is defined as:
|
All the collected usage information of the measured streams are encoded in an HTTP request and regularly transmitted to the measuring system. The following rules apply:
// System Object [{"sx":1280, "sy":1024, "pl":"FlashPlugin", "plv":"WIN 10,0,45,2" }, // Usage Information {"stream":"spring/teststream", "dur":"600", "sx":"400", "sy":"300", "uid":"267fgut", "vt":356, "pst":[[0,0,"kzog7e"],[22,378,"kzog7e"]] }] |
Two objects are sent by the data transport:
The system object that contains information such as screen resolution, player name and player version.
Variable | Optional? | Description |
---|---|---|
| No | The width of the screen in pixel |
| No | The height of the screen in pixel |
| No | The player name |
| No | The player version |
The usage information of a measurement
Variable | Optional? | Description |
---|---|---|
| No | The player version |
| No | The stream name |
| No, if it isn't a live stream. | The stream length in seconds |
| No | The width of the stream window in pixel or the value |
| No | The height of the stream window in pixel or the value |
| No | The unique Id of the viewing sequence |
| No | The view time in seconds. It's measured from the call to the method |
| No | The play states. The list of viewing intervals on the stream. |
The description of the Encoding for the HTTP request is not part of this documentation. The request is designed in a manner that the variables are still clearly identifiable during debugging activities. |
Prior to using the springStreams-functions the Javascript-library must be loaded.
This is achieved by the following script-tag:
<script src=".../springstreams.js"></script> |
The springStreams-functions are provided by the class SpringStreams
. The code of a site will be passed on with the creation of an object of this class:
var sensors = new SpringStreams("test"); |
test
= The site code in this case is “test”. You have to replace the site code "test" by the site code (unique name provided by Kantar) for the measured site.
To measure any player – even proprietary ones – an adapter to the specific player can be used to pass on data to the sensors of the measurement system. This adapter provides the following three functions:
var myAdapter = { "getMeta" : function(id) { return { "pl" :"own player", "plv" :"version1", "sx" : screen.width, "sy" : screen.height } }, "getDuration" : function(id) { return streamlength in seconds; }, "getPosition" : function(id) { return new Date().getTime() / 1000; } }; |
1. The function getMeta
is used to acquire a description of the player and the available screen area. By calling this function a return of an object with the following attributes is expected:
| player description |
| player version |
| screen width in pixel |
| screen height in pixel |
2. The function getDuration
is used to acquire the total duration of the stream in seconds. If this cannot be done (because it is e.g. a live stream) 0
should be returned.
3. The function getPosition
is used to acquire the current position in the stream. The function delivers the current play position in seconds. This function is also used to determine the intervals within the streams being played, skipped or stopped.
By calling the object to be measured (from the first parameter of the call to sensors.track(…)
) it will be transmitted to all functions.
The self-created adapter can now be used for the measurement:
In the next step the stream content, the description object and the adapter can be transmitted to the API method track
.
sensors.track(someObject, desc, myAdapter); |
The measurement can be monitored by using the method debug
on the SpringStreams
object:
sensors.debug = function(v) { window.status = " " + v; } |
Upon each transmission of the sensor to the measurement system this method is attached as a parameter (string) to the URL called.
SpringStreams
does not intervene with the event model of the surrounding document. Therefore it is necessary to notify the sensors of any termination event of the streams by using events outside of the player. The most simple option for such a method is the insertion of an unload
function by calling the method sensors.unload()
, when the website is left by the user:
function unload() { sensors.unload(); } |
Because the browser will close the web site after the unload sequence is finished, it is possible that the closing counting impulse was not committed. An improvement can be achieved by inserting a piece of code at the end of the unload sequence.
function unload() { sensors.unload(); // give time for submission var start= new Date(); var now = null; do now = new Date(); while(now-start < 100); } |
To do so, this function can be added into the body tag:
<body onunload="unload();"> |
Single streams can also be terminated directly, for example by changing the play list:
var stream = sensors.track(someObject, desc, myAdapter); ... stream.stop(); |
For other embedded players than the WMP, an adapter can be used. Find below an example for the Real Player with the id rvplayer
:
sensors.track(rvplayer, description, sensors.RVStreamAdapter); |
Example for a proprietary player
<html> <head> <title>spring sensors</title> <script src="springstreams.js"></script> </head> <body onunload="unload();"> <script type="text/javascript"> var sensors = new SpringStreams("test"); var adapter = { "getMeta" : function() { return { "pl" :"own player", "plv" :"version1", "sx" : screen.width, "sy" : screen.height } }, "getDuration" : function() { return streamlength in seconds; }, "getPosition" : function() { return new Date().getTime() / 1000; } }; var desc = { "stream": "videos/teststream" } sensors.track("someid", desc, adapter); // uncomment for debugging // sensors.debug = function(v) { // window.status = v; // } function unload() { sensors.unload(); // give time for submission var start= new Date(); var now = null; do now = new Date(); while(now-start < 100); } </script> </body> |
Prior to using the springStreams-functions the Javascript-library must be loaded.
This is achieved by the following script-tag:
<script src=".../springstreams.js"></script> |
The springStreams-functions are provided by the class SpringStreams
. The code of a site will be passed on with the creation of an object of this class:
var sensors = new SpringStreams("test"); |
test
= The site code in this case is “test”. You have to replace the site code “test” by the site code (unique name provided by Kantar) for the measured site.
A media player embedded into the website can now be measured directly. For this, the object which is to be measured is required. In most cases this will be available through the id
of the object’s tag. In the following example an object with the ID wmplayer
with a reference to the Windows Media Player is being used.
sensors.track(wmplayer, {}); |
Beyond the ID of the object a number of descriptive information can be passed on in form of a JavaScript object:
var description = { "stream": "videos/teststream" "desc": "some additional description" }; sensors.track(wmplayer, description); |
It is possible to include more additional attributes to the description. The declaration of stream
with the name or the hierarchy of the stream is expected as a minimum.
More than one object can be measured.
Example Windows Media Player
<html> <head> <title>spring sensors</title> <script src="springstreams.js"></script> </head> <body onunload="unload();"> <SCRIPT type="text/javascript"> if(-1 != navigator.userAgent.indexOf("MSIE")) { document.write('<OBJECT id="wmplayer" width="435" height="326" CLASSID="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" type="application/x-ms-wmp">'); document.write(' <param name="URL" value="http://wstreaming.zdf.de/zdf/veryhigh/070912_iaa_mim.asx">'); document.write(' <param name="AutoStart" VALUE="1">'); document.write(' <param name="ShowStatusBar" VALUE="1">'); document.write('</object>'); } else { document.write('<OBJECT id="wmplayer" width="435" height="326" type="application/x-ms-wmp">'); document.write(' <param name="URL" value="http://wstreaming.zdf.de/zdf/veryhigh/070912_iaa_mim.asx">'); document.write(' <param name="AutoStart" VALUE="1">'); document.write(' <param name="ShowStatusBar" VALUE="1">'); document.write(' </object>'); } </SCRIPT> <script type="text/javascript"> // "test" is the name of the tracked website var sensors = new SpringStreams("test"); // wmplayer is the id of the stream above sensors.track(wmplayer, {"stream":"videos/teststream"}); // uncomment for debugging //sensors.debug = function(v) { // window.status = v; //} function unload() { sensors.unload(); // give time for submission var start= new Date(); var now = null; do now = new Date(); while(now-start < 100); } </script> </body> |
Before using the springstreams-functions, the javascript library has to be uploaded. This is done via the following script-tag:
<script src=".../springstreams.js"></script> |
The springstreams-functions are available via SpringStreams
class. During creation of an object in this class, the website-identification is transferred:
var sensors = new SpringStreams("test"); |
test
is the identification of the website in this case. This identification has to be replaced by the own identification provided by Kantar.
A video
- or audio
element (see: http://www.w3schools.com/tags/ref_av_dom.asp) embedded into the website can now be measured directly. In order to perform the measurement, the object to be measured is needed. Usually this is available via the id
of the object-tag. In this example, the object with the ID video5
is used with a reference to an HTML video element.
sensors.track(video5, {}); |
In addition to the ID of the object to be measured, descriptive information concerning the object in form of Javascript-object can be indicated:
var description = { "stream": "videos/teststream" "desc": "some additional description" }; sensors.track(video5, description); |
There is the possibility to add additional attributes to the description. Minimum the identification of stream
indicating the name/hirarchy of the stream is expected.
Example HTML5 video
<!DOCTYPE html> <html lang="en"> <head> <title>HTML5 Video Example</title> <script src="./springstreams.js"></script> </head> <body onunload="unload()"> <script type="text/javascript"> var sensors = new SpringStreams("test"); </script> <div align="center"> <video id='video' controls preload='none' > <source id='mp4' src="./wetter.ard.20101209.mp4" type='video/mp4; codecs="avc1, mp4a"'></source> <p>Your user agent does not support the HTML5 Video element.</p> </video> </div> <script type="text/javascript"> var description = { "stream":"videos/news/wetter.ard.20101209.mp4" }; var handle = sensors.track(video, description, sensors.HTML5Adapter); function unload() { sensors.unload(); } </script> </body> </html> |
The implementation in Flash is similar to the one in Javascript. To use the springStreams
functions the library springstreams.as3.swc
(resp. springstreams.as2.swc
for Actionscript2) is embedded into the application.
Now the springStreams-functions are available via the class SpringStreams
. When an object of this class is created, the name of the website is being passed on:
var sensors:SpringStreams = new SpringStreams("test"); |
test
= The site code in this case is “test”. You have to replace the site code “test” by the site code (unique name provided by Kantar) for the measured site.
The measurements are passed on via an http call to the measurement systems. In the case that this call should be done via SSL (HTTPS) this can be achieved by passing on this information to the sensor:
var sensors:SpringStreams = new SpringStreams("test", true); |
A NetStream object can now be measured directly:
sensors.track(ns,{}); |
Beyond the ID of the object a number of descriptive information can be passed on as a JavaScript object:
var description:Object = { "stream": "videos/teststream", "desc": "some additional infos", "sx": video.width, "sy": video.heigth, }; sensors.track(ns, description); |
It is possible to include more additional attributes to the description. The declaration of stream
with the name of the stream or the hierarchy and sx
respectively sy
with the sizing description of the visible area is expected as a minimum.
Requests to the measurement system can be monitored via the ActionScript function trace
in the debug environment.
The class SpringStreams
defines a function SPRING_UNLOAD
via the Flash class ExternalInterface
(if available). Analogous to the Javascript version, this function can be used to signal the termination of the runtime environment. This can be implemented as follows:
<body onunload="unload()"> ... function unload() { FlexProject.SPRING_UNLOAD(); } |
Because the browser will close the web site after the unload sequence is finished, it is possible, that the closing counting impulse was not initiated. An improvement will be reached by inserting a part of a little application at the end of the unload sequence, which will not be noticed by customers.
function unload() { FlexProject.SPRING_UNLOAD(); // give time for submission var start= new Date(); var now = null; do now = new Date(); while(now-start < 100); } |
FlexProject
is the ID of the flash object. If the Flash application already uses an unload mechanism, this mechanism can call the static function SpringStreams.unload()
.
If the player should be used as Embedded Player on an other website, the security settings have to be respected.
The following settings must be setup (siehe: ExternalInterface#addCallback())
Set in the HTML page at the object tag for the SWF file the following parameters:
<param name="allowScriptAccess" value="always" /> |
Paste in the SWF file the following ActionScript code:
flash.system.Security.allowDomain( sourceDomain ) |
At absence of these settings, a security error appears in the API, because the trial of registering the SPRING_UNLOAD()
function on the website will fail. This error is handled by the API and will be ignored. However, it isn't essential for the proper functioning of the measurement.
Furthermore, for the proper functioning the entry of the attribute onunload="..."
in the body
tag is necessary in order to report the leaving of the side to the API. At absence of these settings, it's possible that the last event at the end of the measurement is no longer transmitted to the measurement system.
Example integration in Flash
var nsClient:Object = {}; nsClient.onMetaData = ... nsClient.onCuePoint = ... nc = new NetConnection(); nc.connect(null); ns = new NetStream(nc); ns.play(streamlocation); ns.client = nsClient; video = new Video(); video.attachNetStream(ns); addChild(video); var tracker:SpringStreams = new SpringStreams("test"); tracker.track(ns,{"stream":"videos/teststream","sx":video.width,"sy":video.height}); |
The determination of the stream’s total duration is achieved by an intermediate stream-client, which accesses all meta-events of the stream. This stream-client transparently routes all events to the already registered client (nsClient in the above example).
A meta event (onMetaData
) containing an info-object is expected. The attribute duration
(info.duration
) is requested from this info-object and interpreted as the length of the stream.
If this information should not be provided by your streams, the duration of the stream can be assigned externally (in seconds).
via the stream reference:
var nsClient:Object = {}; nsClient.onMetaData = ... nsClient.onCuePoint = ... nc = new NetConnection(); nc.connect(null); ns = new NetStream(nc); ns.play(streamlocation); ns.client = nsClient; video = new Video(); video.attachNetStream(ns); addChild(video); var tracker:SpringStreams = new SpringStreams("test"); var stream:Stream = tracker.track(ns,{"stream":"videos/teststream","sx":video.width,"sy":video.height}); stream.setDuration(600/*10 minutes*/); |
As described in the last chapter, you need a library for a flash.net.NetStream
object to measure a streaming content. Inside the measurement, the actual position on the stream object will be readout.
The measurement is constantly calling the property NetStream.time
.
var net:NetConnection = new NetConnection(); net.connect(null); var ns:NetStream = new NetStream(net); var currentPosition:Number = ns.time; |
With this knowledge it is possible to measure any streaming object, where the actual position in seconds on the stream is transmitted.
For this you have to implement an own NetStream
object and overwrite the call ns.time
.
In the following example a NetStream
adapter for the flash.media.Sound
object is implemented.
package { import flash.media.SoundChannel; import flash.net.NetConnection; import flash.net.NetStream; public class SoundNetStreamAdapter extends NetStream { private var channel:SoundChannel; public function SoundNetStreamAdapter(net:NetConnection, c:SoundChannel) { super(net); channel = c; } override public function get time():Number { // return the position in seconds return channel.position/1000; } } } |
This adapter is also a NetStream
object and can be transmitted to the streaming library. By implementing, the property time
is overwritten. This property delivers the actual position in seconds. This value is divided by 1000 because the SoundChannel
object delivers milliseconds instead of seconds. This is necessary to adapt the interface description of the NetStream
object.
The length of the stream is taken by the property Sound.length
, transformed to seconds and is written into the description object with the name duration
.
var tracker:SpringStreams = new SpringStreams("test"); var s:Sound = new Sound(); s.load(new URLRequest("file:///pathto/sound.mp3")); var desc:Object = { "stream":"sounds/sound.mp3", "sx":0,"sy":0, }; var nc:NetConnection = new NetConnection(); nc.connect(null); var ns:NetStream = new SoundNetStreamAdapter(nc, s.play()); var stream:Stream = tracker.track(ns, desc); stream.setDuration(s.length/1000); // duration in seconds |
Possibly there is a need for a deeper/different segmentation of streams. This can be desirable in case of a live stream or recorded streams with several content parts, so that the individual segments or parts of the stream can be distinguished.
This can also be realized with the library by measuring each consignment separately. To do this, the player needs to know when and what is broadcasted. It simply needs something like a program structure or "play list".
Example for the measurement of individual segments or parts on a live stream
var nsClient:Object = {}; nsClient.onMetaData = ... nsClient.onCuePoint = ... nc = new NetConnection(); nc.connect(null); ns = new NetStream(nc); ns.play(streamlocation); ns.client = nsClient; video = new Video(); video.attachNetStream(ns); addChild(video); // 20:00 - 20:15 Tagesschau // 20:15 - 21:00 PlusMinus var tracker:SpringStreams = new SpringStreams("test"); // 20:00 var stream:Stream = tracker.track(ns,{"stream":"livestreams/ard/Tagesschau","sx":video.width,"sy":video.height}); // 20:15 stream.stop(); stream = tracker.track(ns,{"stream":"livestreams/ard/PlusMinus","sx":video.width,"sy":video.height}); |
The library is able to measure several streams in parallel. All the streams which have been started can be measured directly by being transmitted with the method “track” to the measurement of streaming.
Example for the measurement of two parallel streams
... ns1 = new NetStream(...); ... ns2 = new NetStream(...); ... var tracker:SpringStreams = new SpringStreams("test"); var stream1:Stream = tracker.track(ns1,{"stream":"streams/stream1","sx":video.width,"sy":video.height}); var stream2:Stream = tracker.track(ns2,{"stream":"streams/stream2","sx":video.width,"sy":video.height}); |
The user can be informed at some point that the application monitors the user actions and transmits them to a measuring system. Furthermore, the user must be informed that he has the possibility to switch of the tracking in the application and can contradict this way. (see: Implementation of Stream Measurement#Opt-Out)
For this purpose, you can include data privacy information in your language into an appropriate place of your app implementation:
Our app uses the "mobile app streaming sensor" of Kantar Media spring, Saarlouis, Germany, to gather statistics about the usage of our site. This data is collected anonymously. Please note that only the measurement of our app is disabled. It may be that you will continue to be measured by other broadcasters using the "mobile app streaming sensor". Mobile App Streaming Sensor Measurement: |On/Off| |
The application developer can give users the ability to stop the further tracking of the user actions. For this purpose the library offers the following methods:
/** * When the value <code>false</code> is specified, the sending of * requests to the measuring system is switched off. * This value is <code>true</code> by default. */ public void setTracking(boolean tracking) { } /** * Delivers the value <code>true</code> when the tracking * is activated otherwise the value is <code>false</code>. */ public boolean isTracking() { } |
A persistent saving of the opt-out decision in the library is not provided and needs to be implemented by the app developer. |