Skip to main content

Metrics

fl-analytics is an add-on library that serves as a framework for recording comprehensive data metrics related to application, video playback, video downloads, and user events. The library can also be used to collect custom events and metadata. The library's data model is based on the Data Dictionary which is the standard schema used to normalize every piece of data captured in order to generate many popular video streaming quality of experience metrics.

QP Analytics offers extensions for the following analytics tools, enabling client applications to seamlessly interact with them through simplified public APIs:

  1. Datazoom
  2. Conviva

Below are the steps for setting up and integrating each tool.

Setup

Quickplay's Player QOE metrics module with Conviva SDK which is a real-time analytics platform designed to optimize video streaming experiences. It provides insights into viewer engagement, streaming quality, and audience behavior, helping content providers improve performance and maximize user satisfaction. Through data-driven metrics, enables better decision-making for live and on-demand video services.
  1. Add the following dependencies for Conviva in your Application's build.gradle file's dependencies block.
dependencies {
implementation 'com.conviva.sdk:conviva-core-sdk:4.0.39'
implementation 'com.conviva.sdk:conviva-exoplayer-sdk:4.1.3'
}
  1. Add the following Moshi-Kotlin dependency, which QP Analytics library uses internally to convert kotlin native obejcts to collections and vice verse
dependencies {
implementation 'com.squareup.moshi:moshi-kotlin:1.9.1'
}

Create Application Session

ApplicationSession provides the entry point to the library analytics protocols. It also serves as factory containing APIs to create other analytic sessions (PlaybackSession, UserSession, DownloadSession). Besides this ApplicationSession also provides APIs for reporting app start and report fatal and non-fatal errors.

Create ApplicationSession using the relevant APIs, creation of each parameter is briefed below

val appSession = ApplicationSession.createInstance(
configuration,
connectionListener,
commonData,
customEventsConfigEndpoint
)

ApplicationSession.getInstance()

// API to create PlaybackSession
appSession.createPlaybackSession()

// API to create UserSession
appSession.createUserSession()

// API to create DownloadSession
appSession.createDownloadSession()
note

Since ApplicationSession is a singleton class, ApplicationSession.createInstance should be called only once and ApplicationSession.getInstance should be used to access the ApplicationSession object thereafter. Also note that ApplicationSession acts as a factory to create the remaining analytics session instances(UserSession, PlaybackSession, DownloadSession).

The library supports connection to multiple analytics provider (supports Datazoom, Conviva at present) by create configuration to specific analytic provider, below is the section for creating configuration for respective analytics module.

Create Analytics Configuration

Create configuration to initialize conviva.
NameRequiredDescription
customerKeytrueThe unique identifier of the Conviva configuration key.
gatewayURLfalseThe url for show-casing playbackSession on touchstone (A Conviva tool designed to assist in debugging and validating the integration of Conviva’s video sensor with streaming applications and platforms.).
allowBackgroundDataCapturefalseTracks metrics even when the application goes to background if the value is set to true. Default is set to false.
setLogLevelfalseSet logger level for additional logs to debug, below is the table with possible enum values
NameDescription
ConvivaLogLevel.DEBUGTo set debug level logs.
ConvivaLogLevel.INFOTo set info level logs.
ConvivaLogLevel.WARNINGTo set warning level logs.
ConvivaLogLevel.ERRORTo set error level logs.
ConvivaLogLevel.NONEfallback value
val configuration = ConvivaConfiguration(
<provided customer key from conviva>,
appContext = applicationContext,
)
danger

gatewayURL has to be set only on debug builds if required, this should never be enabled on production build

Create Analytics Connection Status Listener

The library client can start reporting events only if successful connectivity has been established to analytics system and AnalyticsConnectionStateListener API provides the connectivity status.

val connectionListener = object : MetricsConnectionStateListener {
override fun onSuccess() {
// write logic for the case when connected to analytics system.
}

override fun onFailure(error: Error) {
// write logic for the case when we not connect to analytics system. Check the error for reason.

}
}

Create Common Data

note

When intergrating Conviva just provide the basic parameters provided below to create ApplicationSession which is marked as required true as Conviva is mainly player metrics focusses tool.

The Metadata that is expected to remain constant for the entire duration of a session should be provided using CommonReportingData. It encapsulates all relevant optional and mandatory metadata regarding different aspects of the AnalyticSession.

note

Use API to update any of this common reporting data.

Application

Create application reporting data payload.

NameTypeRequiredDescription
nameStringtrueThe name of the application.
versionStringtrueThe version of the application.
buildVersionStringtrueThe build version of the application.
productStringfalseThe customer product.
User
note

When integrating Conviva, the id for the USER type is mandatory, as Conviva categorizes data based on the user's ID, follow below snippet to initialize it.

val user = User(
UserType.ANONYMOUS // modify this as per user type
)

user.id = <userId collected by your system>

Create user's reporting data payload.

NameTypeRequiredDescription
typeUserTypetrueIndicates appropriate user type.
idStringfalseThe unique user identifier (eg: Customer Id)
subscriptionSubscriptionfalseUser subscription details.
profileIDStringfalseThe unique identifier for the user's profile
Subscription

Create Subscription reporting data payload which will be reported as part of above user's payload.

NameTypeRequiredDescription
subscriptionIdStringtrueThe unique subscription identifier for the user.
subscriptionStatusSubscriptionStatusfalseIndicates appropriate subscription status.
subscriptionPlanStringfalseThe subscription plan type name.
subscriptionPlanIDStringfalseThe subscription plan type id
Device

Create user device's reporting data payload.

NameTypeRequiredDescription
platformTypePlatformTypetrueRepresents how user consuming service (eg: APP, WEB)
customDeviceManufacturerStringfalseThe manufacturer of the user's device if available.
customDeviceNameStringfalseThe name of the device model if available.

Create CommonReportingData that has to be reported across all the events for the entire application lifecycle.

NameTypeRequiredDescription
appApplicationtrueThe Application instance
userUserfalseThe User instance.
deviceDevicefalseThe Device instance.
val appInfo = Application("sample", "1", "1")
val userInfo = User(UserType.SUBSCRIBED)
val deviceInfo = Device(PlatformType.APP)

val commonData = CommonReportingData(
appInfo,
userInfo,
deviceInfo
)

Toggle Custom Events

Custom Events reporting to the Analytics server can be toggled on/off remotely. Passing the config end point URL, where the black-listed items are hosted, to the createInstance will restricts the reporting of black-listed custom events

NameTypeRequiredDescription
customEventsConfigEndpointStringfalseThe end point where custom events configuration details are hosted

Standard Playback Events & Metrics

Create Playback Session

Create PlaybackSession to report player related events.

val playbackSession = appSession.createPlaybackSession()

Attach Player

note

Call above attachPlayer API right after player has been created using PlayerBuilder. When composing the player (with IMA, Yospace, or Brightcove), invoke the attachPlayer API immediately after the player is composed with the said additional capabilities.

PlaybackSession provides and API called attachPlayer which takes Player instance as parameter. This API enables the underlying analytics collection tool to access platform native player instance, therefore auto-reporting most of the playback related events.

playbackSession.attachPlayer(player: Player)
note

Call above attachPlayer API once player has been loading, Listen for PlaybackState.LOADING state (refer Here).

Playback events that are auto-captured by library itself

NameDescription
pauseThis event is reported when the player is paused.
resumeThis event is reported when the user begins playing after pausing the video.
buffer_startBuffer Start identifies anytime the player has to wait for the video buffer to fill with video segments.
buffer_endEvent is reported when video starts playing again after a buffer is completed.
player errorThrown if an error occurs during content playback or retrieval of the video.
seek_startThis event records when the user interacts with time controls within the player to move forward or backward in the video timeline.
see_endEvent is reported when the player stops moving the playhead position to jump to a specific point on the timeline.
playingThe media is no longer blocked from playback, and has started playing. Reported when playback resumes from Stall, Buffering or Seek.

Report Custom Playback Events

note

The Android implementation of fl-analytics library does not provide support for multiple concurrent playback event reporting.

Report Playback Start

PlaybackSession provides API to report playback_request event.

PlaybackRequest
Content Specific metadata

Create data payload for specific type of contents as below.

SportContent

Create SportContent reporting data payload that is specific to sport event.

NameTypeRequiredDescription
idStringtrueThe unique identifier for content item.
typeStringtrueThe type of content to report.
nameStringfalseThe content name from CMS.
providerIdStringfalseThe content's provider identifier.
genreStringfalseThe genre of the content.
licenseWindowStartDateStringfalseThe license window start date. The clear content may not have this parameter.
sportNameStringfalseThe name of the sport.
leagueNameStringtrueThe name of the sport league.
team1NameStringfalseThe name of the first sport team.
team2NameStringfalseThe name of the second sport team.
leagueIDStringfalseThe unique identifier of the sport league.
leagueExternalIDStringfalseThe external unique identifier of the sport league.
leagueShortNameStringfalseThe short name of the sport league.
gameIDStringfalseThe unique identifier of the sport game.
gameExternalIdStringfalseThe external unique identifier of the sport game.
venueNameStringfalseThe name of the sport event venue.
venueCityStringfalseThe city where the sport event takes place.
venueCountryStringfalseThe country where the sport event takes place.
team1IDStringfalseThe unique identifier of the first sport team.
team1ExternalIDStringfalseThe external unique identifier of the first sport team
team1ShortNameStringfalseThe short name of the first sport team.
team2IDStringfalseThe unique identifier of the second sport team.
team2ExternalIDStringfalsehe external unique identifier of the second sport team.
team2ShortNameStringfalseThe short name of the second sport team.
TVShow

Create TVShow reporting data payload that is specific to TV show.

NameTypeRequiredDescription
idStringtrueThe unique identifier for content item.
typeStringtrueThe type of content to report.
nameStringfalseThe content name from CMS.
providerIdStringfalseThe content's provider identifier.
genreStringfalseThe genre of the content.
licenseWindowStartDateStringfalseThe license window start date. The clear content may not have this parameter.
seriesIDStringtrueThe unique identifier of the TV show series.
seriesNameStringtrueThe name of the TV show series.
seasonNumberStringtrueThe season number of the TV show series.
episodeNumberStringtrueThe number of one of the episodes in the TV show series.
MiscellaneousContent

Create MiscellaneousContent video content reporting data payload that belongs to categories other than SportContent or TVShow.

NameTypeRequiredDescription
idStringtrueThe unique identifier for content item.
typeStringtrueThe type of content to report.
nameStringfalseThe content name from CMS.
providerIdStringfalseThe content's provider identifier.
genreStringfalseThe genre of the content.
licenseWindowStartDateStringfalseThe license window start date. The clear content may not have this parameter.
note

If the content type do not fall under any of the categories like SportContent and TVShow then create Content as MiscellaneousContent.

ApplicationContainer

Create ApplicationContainer reporting data payload related to application container.

NameTypeRequiredDescription
idStringtrueThe unique identifier of the carousel where the content or link to the collection is located.
nameStringtrueThe name of the carousel where the content or link to the collection is located.

Create PlaybackRequest reporting data payloads related to video playback request event.

NameTypeRequiredDescription
contentContenttrueThe Content details.
playbackSourcePlaybackSourcefalseThe PlaybackSource details.
containerApplicationContainerfalseThe ApplicationContainer details.
val container = ApplicationContainer("456", "Movies")
val playbackSource = PlaybackSource(PlaybackSourceType.CAROUSEL)

// For MiscellaneousContent
val contentInfo = MiscellaneousContent("12345", "movie", "Sample Content")

// For SportContent
val contentInfo = SportContent("1234", "sport_show")

// For TVShow
val contentInfo = TVShow("2345", "Magic Show", "1", "5")

val playbackRequest = PlaybackRequest(contentInfo, playbackSource, container)
playbackSession.start(playbackRequest)

Handling Playback Request Interruptions

Any interruptions prior to starting the playback (before creating a player) can be reported using PlaybackSession API. Example: Checks related to content authorization (content authentication, parental controls etc)

// Report Interruption start
val event = "content_authorization_started"
val reportingData = mapOf("key" to "value")

val customEvent = CustomEvent(event, reportingData)

playbackSession.interruptStart(customEvent)

// Report Interruption end
val event = "content_authorization_success"
val reportingData = mapOf("key" to "value")

val customEvent = CustomEvent(event, reportingData)

playbackSession.interruptEnd(customEvent)

Configure Playback Metadata

Add Playback custom metadata

PlaybackSession provides an API that inserts common metadata to be reported across all playback related events.

playbackSession.addMetadata(
mapOf("key" to "value")
)
Update Playback custom metadata

PlaybackSession provides an API to update common metadata to be reported across all playback related events.

playbackSession.updateMetadataRecord(
mapOf("cc_enabled" , "true")
)

Report Playback Error

To report any error caused like content-auth failure, concurrent streams max limit reached (failure from server but not from player layer as fl-analytics auto-reports player errors) can be reported using stop API in PlaybackSession. Send Error as a parameter(optional) to report playback stop on any error.

playbackSession.stop(error)

Valued Added Events & Metrics

Click to see more details on creating other sessions(User, Download sessions), prefer this section if integrating Datazoom

Application Events

Report Application start

ApplicationSession provides an API to report app_start event along with app start time.

ApplicationMetrics

Create ApplicationMetrics reporting data payload related to application performance metrics.

NameTypeRequiredDescription
startUpTimeMsLongtrueThe time, in milliseconds, it takes to start the application.
appSession.start(
ApplicationMetrics(3000)
)

Report Application End

ApplicationSession provides an API to report app_end event.

 appSession.stop()

User Events

Create UserSession and start session to report user related events.

val userSession = appSession.createUserSession()
userSession.start(Unit)

UserSession provides the following API to report user action based events.

// Called when [User] executes "signup" flow.
userSession.signup(user: User)

// Called when [User] executes "login" flow.
userSession.login(user: User)

// Called when [User] executes "logout" flow.
userSession.logout(user: User)

// Called when [User] executes "create profile" flow.
userSession.createProfile(user: User)

// Called when [User] executes "update profile" flow.
userSession.updateProfile(user: User)

// Called when [User] executes "start subscription" flow.
userSession.startSubscription(user: User)

// Called when [User] executes "purchase subscription" flow.
userSession.purchaseSubscription(user: User)

// Called when [User] executes "change subscription" flow.
userSession.changeSubscription(user: User)

// Called when [User] executes "complete payment" flow.
userSession.completePayment(user: User)
note

It is client application responsibility to ensure that each user action is triggered in the correct sequence.

Download Events

Create DownloadSession to report download related events.

val downloadSession = appSession.createDownloadSession()

Report Download Start

DownloadSession provides API to report download_request event.

DownloadRequest
  1. Create Content, video content reporting data payload based on type of content that is being requested. Create SportContent if sport content was requested or TVShow if TV show content was requested, MiscellaneousContent otherwise.

  2. Create ApplicationContainer reporting data payload related to application container.

  3. Create DownloadRequest reporting data payloads related to video playback request event.

NameTypeRequiredDescription
contentContenttrueThe Content details.
playbackSourcePlaybackSourcefalseThe PlaybackSource details.
containerApplicationContainerfalseThe ApplicationContainer details.
val container = ApplicationContainer("456", "Movies")
val playbackSource = PlaybackSource(PlaybackSourceType.CAROUSEL)

// For MiscellaneousContent
val contentInfo = MiscellaneousContent("12345", "movie", "Sample Content")

// For SportContent
val contentInfo = SportContent("1234", "sport_show")

// For TVShow
val contentInfo = TVShow("2345", "Magic Show", "1", "5")

val downloadRequest = DownloadRequest(contentInfo, playbackSource, container)
downloadSession.start(downloadRequest)

Download events that are auto-captured by library itself

NameDescription
download_preparedThis event is reported when a download is prepared
download_startedThis event is reported when a download is started
download_pausedThis event is reported when a download is paused
download_resumedThis event is reported when a download is resumed
download_stoppedThis event is reported when a download is stopped
download_completedThis event is reported when a download is completed
download_deletedThis event is reported when a download is deleted

Report Custom Events

ApplicationSession provides an API to report custom events. The library provides MiscellaneousEvent names for the client application to reuse.

val customEvent = CustomEvent("sample_event", mapOf("key" to "value"))

appSession.addEvent(customEvent)
note
  1. In order to conform to the existing reporting scheme the event name should be provided in the lower case format and words should be separated by the underscore character e.g."playback_request"
  2. In datazoom, any custom event will be reported as event name with custom_ prefix. (eg: playback_start as custom_playback_start) :::

When trying to report an custom event with a name that is already reserved (the list of reserved event names is captured by QP_ANALYTICS_EVENTS), library will throw an error. :::

Configure Application Metadata

Add Application custom metadata

Any additional metadata that is to be attached to all application / playback / user events can be done using the the below API. All subsequent events will report this additional data once it is defined.

appSession.addMetadata(
mapOf("key" to "value")
)
Update Application custom metadata

ApplicationSession provides an API if the application wants to change any application level attribute at any point of time during the application session.

Example: If the application wants to report the changeable language that it is rendering in, a key - value pair denoting the information can be added using this method. If the language is updated at any point of time during the session, this change can be reflected using below API.

appSession.updateMetadata(
mapOf("catalogue_selected" , "English")
)

Application Errors

ApplicationSession provides APIs to report both fatal and non-fatal errors.

Report Fatal errors

Any application fatal error can be reported using below API. Send Error as a parameter(optional) to report playback stop on any error.

applicationSession.stop(error)

Report Non-fatal errors

Any application non-fatal error can be reported using below API. Send Error to report playback stop on any error.

applicationSession.addErrorEvent(error, null)

Download Errors

Any Download error can be reported using below API. Send Error to report download stop on any error.

downloadSession.stop(error)

User Action Errors

Any User error can be reported using below API. Create UserError reporting data payload in case where one of user's action fails and User attribute along with it.

Create User Error

NameTypeRequiredDescription
codeStringtrueThe unique error code.
messageStringtrueThe message describing the error.
descriptionStringfalseThe contextual description of the error.
val userError = UserError("<error-code>", "user action failure")
val user = User(UserType.SUBSCRIBED)

userSession.addErrorEvent(userError, user)

Out-of-box Player Metrics

Click to know more about out-of-box player reporting metrics

The Quickplay Player provides number of key metrics to analyse the playback performance. Please refer the bundled sample app to understand the corresponding metrics API.

Key Player Metrics

  • Playback Startup Time - Playback startup time is the time taken for player to start the playback measured from the moment playback was requested.

  • BufferedRange - The accumulated duration of the media downloaded in the buffer so far (ratio of currentPosition and bufferedDuration).

  • BufferPercentage - Returns an estimate of the percentage in the current content window or ad up to which data is buffered.

  • DecodedFrameRate - Provides number of frames being decoded (the average bandwidth in bits per second).

  • DisplayedFrameRate - Provides number of Frames being displayed (per second).

  • DroppedDecodedFrameCount - Provides the number of frames that could not be decoded.

  • DroppedDisplayableFrameCount - Provides the number of displayable frames that could not be displayed.

  • AudioDecoderInfo - Provides the audio codec type and name used by player.

  • VideoDecoderInfo - Provides the video codec type and name used by player.

  • ObservedBandwidth - Provides the Observed bandwidth.

  • BandwidthEstimate - Provides the player's current estimate bandwidth.

  • VariantSwitchCount - The number of times video/audio variant switch based on network bandwidth.

The Quickplay Player's StreamInformation and NetworkInformation classes provides all metric info required. For more information please refer sample app.

class MetricsOverlayView(context: Context) : Player.AuxiliaryListener {

override fun onNetworkInfoChanged(networkInfo: NetworkInformation) {
// access here all networkInfo metrics related to playback
}

override fun onStreamInfoChanged(streamInfo: StreamInformation) {
// access here streamInfo metrics related to playback
}
}