This guide walks through integration with Google's ExoPlayer to collect video performance metrics with Mux data.
Features
The features supported by Mux Data for this player.
Install the Mux Data SDK
Download the version of the SDK that matches your version of ExoPlayer.
Initialize the monitor with your ExoPlayer instance
The Mux monitor attaches to your ExoPlayer instance.
Add Metadata
Advanced
Depending on the details of your implementation, you may want to leverage some of the advanced options of MuxStatsExoPlayer.
Java Build Compatibility
Release notes
This documents integration instructions for Google's ExoPlayer
library, version 2.x. ExoPlayer
versions before 2.0 are not supported. As of version 3.0.0 of Mux's integration with ExoPlayer
, only versions of ExoPlayer
greater than or equal to 2.10.x are supported.
The Mux integration with ExoPlayer
is built on top of Mux's core Java SDK, and the full code can be seen here: muxinc/mux-stats-sdk-exoplayer.
The following data can be collected by the Mux Data SDK when you use the ExoPlayer SDK, as described below.
Supported Features:
renditionchange
eventsRequest Latency is not available.
Add the Mux SDK to your project using one of the following approaches:
Add the Mux Maven repository to your Gradle file:
repositories {
maven {
url "https://muxinc.jfrog.io/artifactory/default-maven-release-local"
}
}
Next, add a dependency on the Mux Data ExoPlayer SDK. Supported versions of ExoPlayer are:
amznPort
(see below)There is typically API compatibility within an ExoPlayer major-minor version, so you should be able to pair one of the versions listed above with any player sharing the same major-minor version (e.g., the ExoPlayer r2.12.1 version of the Mux ExoPlayer SDK works with ExoPlayer r2.12.0 and r2.12.2 equally well).
Add a dependency to your Gradle file using the Mux SDK version and an ExoPlayer version listed above in the following format:
api 'com.mux.stats.sdk.muxstats:MuxExoPlayer_(ExoPlayer SDK version with underscores):(Mux SDK version)'
Example using Mux ExoPlayer SDK 2.7.2 and ExoPlayer version r2.16.1:
api 'com.mux.stats.sdk.muxstats:MuxExoPlayer_r2_16_1:2.7.2'
In addition to the versions above, the Mux Data ExoPlayer SDK also supports Amazon's official ExoPlayer port for Amazon Devices. If you are monitoring ExoPlayer on an Amazon device, you can get that version with the following line:
api 'com.mux.stats.sdk.muxstats:MuxExoPlayer_amznPort:(Mux SDK version)'
For an example integration, you can see the demo application within muxinc/mux-stats-sdk-exoplayer which integrates Mux into the ExoPlayer demo application.
Get your ENV_KEY
from the Mux environments dashboard.
ENV_KEY
is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
First, create the CustomerPlayerData
and CustomerVideoData
objects as appropriate for your current playback
val customerData = CustomerData().apply {
customerVideoData = CustomerVideoData().apply {
// Data about this video
// Add or change properties here to customize video metadata such as title,
// language, etc
videoTitle = "Mux ExoPlayer Android Example"
// ExoPlayer doesn't provide an API to obtain this, so it must be set manually
videoSourceUrl = videoUrl
}
customerViewData = CustomerViewData().apply {
// Data about this viewing session
viewSessionId = UUID.randomUUID().toString()
}
customerViewerData = CustomerViewerData().apply {
// Data about the Viewer and the device they are using
muxViewerDeviceCategory = "kiosk"
muxViewerDeviceManufacturer = "Example Display Systems"
muxViewerOsVersion = "1.2.3-dev"
}
customData = CustomData().apply {
// Add values for your Custom Dimensions.
// Up to 5 strings can be set to track your own data
customData1 = "Hello"
customData2 = "World"
customData3 = "From"
customData4 = "Mux"
customData5 = "Data"
}
Next, create the MuxStatsExoPlayer
object by passing your Context
(typically your Activity
), your ENV_KEY
, the ExoPlayer
instance, and the customer data object you just created.
muxStatsExoPlayer = exoPlayer.monitorWithMuxData(
context = requireContext(),
envKey = "YOUR_ENV_KEY_HERE",
playerView = playerView,
customerData = customerData
)
If you haven't set your playerView
already, do so now. We recommend this in order to determine a number of viewer context values as well as track the size of the video player.
muxStatsExoPlayer.setPlayerView(simpleExoPlayerView.getVideoSurfaceView());
Finally, when you are destroying the player, call the MuxStatsExoPlayer.release()
function.
muxStatsExoPlayer.release()
After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your env_key
and look for video views.
On older supported versions of ExoPlayer, Mux prefers that you pass an instance of SimpleExoPlayer
specifically, instead of any ExoPlayer
. In the latter case, however, some metrics and errors may not be available, such as upscaling metrics. Updating to ExoPlayer r2.16.0 or higher will remove this limitation
muxStatsExoPlayer = exoPlayer.monitorWithMuxData(
context = requireContext(),
envKey = "YOUR_ENV_KEY_HERE",
playerView = playerView,
customerData = customerData
)
or in java:
// Make sure to monitor the player before calling `prepare` on the ExoPlayer instance
muxStatsExoPlayer = new MuxStatsExoPlayer(this, "YOUR_ENV_KEY_HERE", player, playerView, customerData);
In the Java SDK, options are provided via the objects within the CustomerData
object.
All metadata details are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.
There is one caveat with ExoPlayer; ExoPlayer does not provide an API to retrieve the current source URL from the player. Due to this, CustomerVideoData
has a method allowing you to set via CustomerVideoData.setVideoSourceUrl(String url)
. Setting this value will allow you to see the source URL as well as the dimension Source Hostname within the dashboard.
For more information, see the Metadata Guide.
There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).
Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).
When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:
This is done by calling muxStatsExoPlayer.videoChange(CustomerVideoData)
which will remove all previous video data and reset all metrics for the video view. See Metadata for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with video
.
It's best to change the video info immediately after telling the player which new source to play.
In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.
In this case, call muxStatsExoPlayer.programChange(CustomerVideoData)
. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See Metadata for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with video
.
For most use cases, the SDK is capable of detecting whether or not a video is being played full-screen. Specifically, it can do so in the case where the player view is the same size as the device display (excepting ActionBars and other framework window decoration).
For other uses cases (non-overlaid controls, window decoration via plain View
s, etc) you may need to tell the SDK when the user switches to full-screen.
If you are using SimplePlayerView
or a similar ExoPlayer UI component, you can set the full-screen flag from the OnFullScreenModeChangedListener
.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// If you are using SimplePlayerView, StyledPlayerView, etc
playerView = findViewById(R.id.my_player_view)
playerView.setFullscreenButtonClickListener { isFullScreen ->
// Set presentation based on which mode is requested
if(isFullScreen) {
muxStats.presentationChange(MuxSDKViewPresentation.FULLSCREEN)
} else {
muxStats.presentationChange(MuxSDKViewPresentation.NORMAL)
}
// Handle moving to fullscreen playback with your code
}
}
By default, Mux's integration with ExoPlayer automatically tracks fatal errors as thrown by ExoPlayer. If a fatal error happens outside the context of ExoPlayer and you want to track it with Mux, you can call muxStatsExoPlayer.error
like this:
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
val errorCode = 1
val errorMessage = "A fatal error was encountered during playback"
val errorContext = "Additional information about the error such as a stack trace"
val error = MuxErrorException(errorCode, errorMessage, errorContext)
muxStatsExoPlayer.error(error)
Note that muxStatsExoPlayer.error(MuxErrorException e)
can be used with or without automatic error tracking. If your application has retry logic that attempts to recover from ExoPlayer errors then you may want to disable automatic error tracking like this:
muxStatsExoPlayer.setAutomaticErrorTracking(false)
It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.
If you are using Google's IMA SDK to play back ads within your Android application, you can configure Mux to monitor the ad performance by passing your instance of AdsLoader
to muxStatsExoPlayer.monitorImaAdsLoader(adsLoader)
.
// For example, within the r2.12.x demo application
// PlayerActivity.getAdsLoader
adsLoader = ImaAdsLoader.Builder(context = this)
/*
* This replaces `monitorImaAdsLoader` method because in r2.12.x ImaAdsLoader
* will create google.v3.AdsLoader on adRequest, which means that monitorImaAdsLoader
* Will always receive null pointer and will be unable to recieve add events.
*/
.setAdErrorListener(muxStats.getAdErrorEventListener())
.setAdEventListener(muxStats.getAdEventListener())
.build()
// Within setting up the AdsMediaSource
sdkFactory = ImaSdkFactory.getInstance()
adsLoader = sdkFactory.createAdsLoader(this)
muxStatsExoPlayer.monitorImaAdsLoader(adsLoader)
As of version 1.3.0
and later, the Mux SDK for ExoPlayer supports firing an event when the playback orientation changes. You can trigger this by calling muxStatsExoPlayer.orientationChange(MuxSDKViewOrientation orientation)
, passing either MuxSDKViewOrientation.LANDSCAPE
or MuxSDKViewOrientation.PORTRAIT
depending on the current orientation of the player.
Starting with version 2.6.0
, the Mux SDK for ExoPlayer requires JDK 11 and version 7.0 or greater of the Android Gradle Plugin. This is only a requirement for build compatibility. The Mux SDK for ExoPlayer will remain bytecode-compatible with Java 1.8.
If you are updating from version 2.5.9
or lower, you may need to:
2020.x
or greater7.0.0
or greatergradle-wrapper.properties
to 7.0.2
or greaterBuild, Execution and Deployment
-> BuildTools
-> Gradle
Gradle JDK
option is not set to a Java 11 JDK, click the dropdown and select a Java 11 JDK. It should be the default on Studio 2020.x
New:
Updates:
Improvements:
Fixes:
Updates:
CustomerViewerData
Fixes:
Improvements:
Improvements:
Fixes:
API Improvements:
Activity
and PlayerView
when you make your MuxStatsExoPlayer
ENV_KEY
is now a required parameter to create a MuxStatsExoPlayer
. It's required, so it's been made mandatory. The existing (non-env-key) constructors are now deprecatedPlease refer to the new usage guide for more details
APIs Removed:
MuxExoPlayer
. Use CustomerData
insteadMuxExoPlayer.setStreamType()
as it was no longer usedgetPlayerData()
, getCurrentPosition()
, etc that are not meant for public useThe full list of removed methods is long, but the change is unlikely to impact you if you are using the SDK as documented. You can review the complete list of removed APIs on our Release page on GitHub
Commit Changelog: Breaking:
Updates:
Improvements:
Fixes:
setPlayerSize
to treat input as physical pixels, as documented. If you are using setPlayerSize()
, you may have to update your codeImprovements:
v2.18.1
v7.3.1
MuxCore Changes:
Improvements:
7.3.0
MuxCore Changes:
Improvements:
v7.2.0
Fixes:
MuxCore Changes:
Improvements:
7.3.0
MuxCore Changes:
Improvements:
v7.2.0
Fixes:
MuxCore Changes:
Fixes:
MuxCore v7.2.0 Changes:
CustomerPlayerData
Fixes:
Fixes:
Improvements:
v2.17.x
Fixes:
requestcompleted
events to prevent ingestion errors when the DataSource
enters a retry loopMuxCore 7.0.10 Fixes:
Improvements:
Fixes
MuxCore 7.0.7 and 7.0.8 Changes:
Improvements:
MuxCore 7.0.6 Changes
MuxCore 7.0.7 Changes
Improvements:
Fullscreen
enum and APIFixes:
-donotwarn
for ExoPlayer classesImprovements:
Fixes:
Fixes:
deployVariant
task. Includes a change to the Gradle package layout, see example in docs.Fixes:
Fixes:
Improvements:
Fixes:
Improvements:
Fixes:
px
to dpx
on setScreen
sizecheckstyle
task to Gradlevideochange
, fixing an issue where rebuffering may be reported incorrectly after calling videochange
viewEnd
event on player release.customerViewData
was not propagated correctly through all constructorscustomerViewData
was not propagated correctly through constructorsmux_viewer_id
view_session_id
wasn't sent correctlywired
instead of ethernet
for certain connection typesprogramchange
viewer_connection_type
, which is a breaking change for IDevice
, as it adds another method that must be implementedview_session_id
, which includes an additional CustomerViewData
class. This changes the constructor for creating a MuxStats
instanceMuxStatsExoPlayer
CustomerViewData
, including setViewSessionId
muxStatsExoPlayer.setPlayerSize(width, height)
those values were not used correctly. Note: If you call this, you must update the player size whenever that changes, as the SDK will no longer pull those values automatically.MuxSDKViewOrientation
to com.mux.stats.sdk.core.MuxSDKViewOrientation
and expose it publiclyRenditionChangeEvent
, which is tracked automaticallyOrientationChangeEvent
, which can be triggered by calling muxStatsExoPlayer.orientationChange(MuxSDKViewOrientation orientation)
. Supported orientations are MuxSDKViewOrientation.LANDSCAPE
and MuxSDKViewOrientation.PORTRAIT
.muxStatsExoPlayer.enableMuxCoreDebug(Boolean enable, Boolean verbose)
muxStatsExoPlayer.updateCustomerData(CustomerPlayerData customerPlayerData, CustomerVideoData customerVideoData)
MuxStatsExoPlayer
is initialized too late, the stream is not tracked correctlyEndedEvent
is not sent to the backendmuxStatsExoPlayer.getImaSDKListener
in favor of muxStatsExoPlayer.monitorImaAdsLoader(adsLoader)
. The previous method will still work, but you should migrate to the new method as the deprecated method will be removed with the next major version.NullPointerException
may occur during playback of a video while tracking bandwidth metrics.programChange(CustomerVideoData customerVideoData)
, for use when inside of a single stream the program changes. For instance, in a long-running live stream, you may have metadata indicating program changes which should be tracked as separate views within Mux. Previously, videoChange
might have been used for this case, but this would not work correctly, and you would not necessarily have seen the subsequent views show up.ExoPlayer
object when release
is called.
getAdaptiveMediaSourceEventListener
and getExtractorMediaSourceEventListener
has been changed. These methods
are used to enable throughput metrics tracking for ExoPlayer versions
before r2.8.0, and now require that the streaming protocol type is
passed as the first parameter. The type is the same as is returned from
this ExoPlayer API call.MuxStatsExoPlayer
constructor
has changed, and now requires an additional parameter (the first) to be
and Android Context
reference.MuxStatsExoPlayer
:
videoChange
setPlayerSize
error
setAutomaticErrorTracking
ExoPlayer
r2.7.xExoPlayer
r2.8.x