Mux

The Mux Developer Hub

Welcome to the Mux developer hub. You'll find comprehensive guides and documentation to help you start working with Mux as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started

Integration Guide: ExoPlayer

Mux Data is the best way to monitor video streaming performance.

Integration is easy - just initialize the Mux SDK, pass in some metadata, and you're up and running in minutes.

Getting Started

This documents integration instructions for Google's ExoPlayer library, version 2.x. ExoPlayer versions before 2.0 are not supported. As of version 1.0.0 of Mux's integration with ExoPlayer, only versions of ExoPlayer greater than or equal to 2.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: https://github.com/muxinc/mux-stats-sdk-exoplayer.

1. Import the Mux Stats ExoPlayer AAR

Mux supports applications utilizing Google's ExoPlayer project. In order to get started, include the Mux SDK for your project by downloading the appropriate AAR for your version of ExoPlayer from our GitHub repo and including it in your project. It is important to use the version of the AAR that matches the version of ExoPlayer that you are using, as ExoPlayer introduces breaking changes often.

We recommend using Android Studio's new module tool which can be accessed via File > New > New Module.... Select the Import .JAR/.AAR Package and then select the mux.aar that you downloaded from our GitHub repo. This should correctly configure the IDE as well as modify your build configuration (Gradle/Maven).

For an example integration, you can see the demo application within this repo which integrates Mux into the ExoPlayer demo application.

2. Add the Mux Stats ExoPlayer monitor

First, create the CustomerPlayerData and CustomerVideoData objects as appropriate for your current playback, and be sure to set your env key.

import com.mux.stats.core.model.CustomerPlayerData;
import com.mux.stats.core.model.CustomerVideoData;
...
CustomerPlayerData customerPlayerData = new CustomerPlayerData();
customerPlayerData.setEnvironmentKey("EXAMPLE_ENV_KEY");
CustomerVideoData customerVideoData = new CustomerVideoData();
customerVideoData.setVideoTitle("The most epic video ever");

Next, create the MuxStatsExoPlayer object by passing your Android Context (typically your Activity), the ExoPlayer instance, a player name, and the customer data objects. Note: Mux prefers that you pass an instance of SimpleExoPlayer, though in the latest versions (r2.8.0+) you can pass an instance of base ExoPlayer; in the latter case, however, some metrics and errors may not be available, such as upscaling metrics.

import com.mux.stats.sdk.muxstats.MuxStatsExoPlayer;
...
// Make sure to monitor the player before calling `prepare` on the ExoPlayer instance
muxStatsExoPlayer = new MuxStatsExoPlayer(ctx, player, "demo-player", customerPlayerData, customerVideoData);

In order to correctly monitor if the player is full-screen, provide the screen size to the MuxStatsExoPlayer instance.

Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
muxStatsExoPlayer.setScreenSize(size.x, size.y);

In order to determine a number of viewer context values as well as track the size of the video player, set the player view.

muxStatsExoPlayer.setPlayerView(simpleExoPlayerView.getVideoSurfaceView());

Depending on the version of ExoPlayer you are using, you may need to attach some listeners to the player and ChunkSource/MediaSource objects. For the latest versions (r2.8.0+), this is handled automatically, but for previous versions, see below.

// MuxStatsExoPlayer automatically registers itself as an
// `AnalyticsListener`, and there is no additional calls
// you need to make for this step.

// In order to track throughput metrics in your application,
// you will need to tell Mux what format you are using for
// adaptive playback, via `muxStatsExoPlayer.setStreamType`

// Example in the ExoPlayer demo application:
@SuppressWarnings("unchecked")
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
  @ContentType int type = Util.inferContentType(uri, overrideExtension);
  // Set the type appropriately.
  muxStats.setStreamType(type);
  switch (type) {
    case C.TYPE_DASH:
      return new DashMediaSource.Factory(...)
        .setManifestParser(...)
        .createMediaSource(uri);
    case C.TYPE_SS:
      return new SsMediaSource.Factory(...)
        .setManifestParser(...)
        .createMediaSource(uri);
    case C.TYPE_HLS:
      return new HlsMediaSource.Factory(...)
        .setPlaylistParser(...)
        .createMediaSource(uri);
    case C.TYPE_OTHER:
      return new ExtractorMediaSource.Factory(...)
        .createMediaSource(uri);
    default: {
      throw new IllegalStateException("Unsupported type: " + type);
    }   
  }
}
/*
 * There are two things that we are need to consider. 
 * First, there is no built in chaining of listeners meaning that 
 * if you already have listeners attached you will need to use the
 * `get*EventListener(*EventListener):*EventListener` function to 
 * wrap your existing listener. 
 * Second, there is no base-class for these listeners which means 
 * that each object requires a different listener to be attached. 
 * Failure to attach the `MuxStatsExoPlayer` listeners to all 
 * appropriate objects will result in at least partially broken 
 * integration.
 * 
 * Note that `MuxStatsExoPlayer` will call `ExoPlayer.addListener`
 * itself.
 */

// getAudioRendererEventListener():AudioRendererEventListener also exists.
player.setAudioDebugListener(muxStatsExoPlayer.getAudioRendererEventListener(eventLogger));

// getVideoRendererEventListener():VideoRendererEventListener also exists.
player.setVideoDebugListener(muxStatsExoPlayer.getVideoRendererEventListener(eventLogger));

// getMetadataRendererOutput():Output also exists.
player.setMetadataOutput(muxStatsExoPlayer.getMetadataRendererOutput(eventLogger));

// getAdaptiveMediaSourceEventListener():AdaptiveMediaSourceEventListener also exists.
new HlsMediaSource(uri, mediaDataSourceFactory, mainHandler,
    muxStatsExoPlayer.getAdaptiveMediaSourceEventListener(eventLogger));

// getExtractorMediaSourceEventListener():EventListener also exists.
return new ExtractorMediaSource(uri, mediaDataSourceFactory, new DefaultExtractorsFactory(),
    mainHandler, muxStatsExoPlayer.getExtractorMediaSourceEventListener(eventLogger));

Finally, when you are destroying the player, call the MuxStatsExoPlayer.release() function.

muxStatsExoPlayer.release()

3. Test it

After you've integrated, start playing a video in the player you've integrated with. Then for your viewing session (called a "video view") to show up in the Mux dashboard, you need to stop watching the video. In a few minutes you'll see the results in your Mux account. We'll also email you when the first video view has been recorded.

4. Add Metadata

Detailed Documentation

In the Java SDK, options are provided via the CustomerPlayerData and CustomerVideoData objects.

All metadata details except for envKey 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.

Changing the video

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 secondly 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).

New Source

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:

  • The player advances to the next video in a playlist
  • The user selects a different video to play

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.

New Program (in single stream)

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.

Error Tracking

By default, Mux's integration with ExoPlayer automatically tracks fatal errors as thrown by ExoPlayer. In some applications, however, you may want to disable this and track errors on your own, especially if you have retry logic in your application to try to recover from errors that ExoPlayer encounters.

In this case, there are two things that you need to do:

  1. Turn off the automatic error tracking. To do this, call muxStatsExoPlayer.setAutomaticErrorTracking(false)

  2. When your application encounters a fatal error that you cannot recover from, call muxStatsExoPlayer.error(MuxErrorException e), including a message and a code.

The following is an example of firing a custom error.

// 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
int errorCode = 1;
String errorMessage = "A fatal error was encountered during playback";
MuxErrorException error = new MuxErrorException(errorCode, errorMessage);
muxStatsExoPlayer.error(error);

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.

Usage with Google Interactive Media Ads (IMA)

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).

// Within setting up the AdsMediaSource
sdkFactory = ImaSdkFactory.getInstance();
adsLoader = sdkFactory.createAdsLoader(this);
muxStatsExoPlayer.monitorImaAdsLoader(adsLoader);

Note: muxStatsExoPlayer.getImaSDKListener(), the previous method for integrating with IMA, has been deprecated as of v0.5.0, and will be removed in a future release.

Additional Events

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.

Advanced Configuration

Sentry

In order to improve our SDKs, Mux utilizes Sentry to track exceptions that our SDK may throw. No personal data is captured by Mux's SDK in these error reports, but if you want to disable this functionality, you can. There are two constructors for MuxStatsExoPlayer, one of which exposes a final boolean parameter that allows you to disable any reporting of crashes to Sentry.

// To disable reporting to Sentry, pass `false` as the last parameter to the constructor
muxStatsExoPlayer = new MuxStatsExoPlayer(ctx, player, "demo-player", customerPlayerData, customerVideoData, false);

Release Notes

Current Release

v1.5.0

  • Fix an issue where if you were using 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.

Previous Releases

v1.4.0

  • Move MuxSDKViewOrientation to com.mux.stats.sdk.core.MuxSDKViewOrientation and expose it publicly

v1.3.0

  • Add support for RenditionChangeEvent, which is tracked automatically
  • Add support for OrientationChangeEvent, which can be triggered by calling muxStatsExoPlayer.orientationChange(MuxSDKViewOrientation orientation). Supported orientations are MuxSDKViewOrientation.LANDSCAPE and MuxSDKViewOrientation.PORTRAIT.
  • Fix an issue where fullscreen tracking was not working correctly

v1.2.0

  • Add support for ExoPlayer 2.11.x
  • Note: there is a known issue right now with ExoPlayer r2.11.x where ads are not tracked correctly. This is under development.

v1.1.0

  • Add support for additional debug logging. See muxStatsExoPlayer.enableMuxCoreDebug(Boolean enable, Boolean verbose)
  • Add the ability to update customerVideoData and customerPlayerData mid-stream, in cases that certain metadata may not be available at the beginning of playback. See muxStatsExoPlayer.updateCustomerData(CustomerPlayerData customerPlayerData, CustomerVideoData customerVideoData)
  • Fix an issue where if MuxStatsExoPlayer is initialized too late, the stream is not tracked correctly
  • Fix an issue where Mux Plugin Version is reported incorrectly
  • Fix an issue where the EndedEvent is not sent to the backend
  • Fix an issue where tracking playback is not correct when playWhenReady is set to false (i.e. non-autoplay playback)
  • Fix an issue where events could be sent after playback completes, forcing the view to be active for longer than it actually was
  • Utilize more accurate client timestamps for event timing

v1.0.0

  • Add support for ExoPlayer 2.9.x
  • Add support for ExoPlayer 2.10.x
  • Fix issue where ExoPlayer versions 2.9.x and greater would log messages about accessing the player on the wrong thread
  • breaking change Removed support for ExoPlayer 2.6.x and older (due to changes in build pipeline and Gradle configurations)
  • Support Gradle 3.5.2

v0.5.1

  • Clean up demo application
  • Allow disabling of Sentry reporting for exceptions.

v0.5.0

  • Deprecated method muxStatsExoPlayer.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.
  • Fix an issue where Google IMA SDK was a hard requirement unintentionally.

v0.4.5

  • Introduce support for tracking ads with Google's IMA SDK.

v0.4.3

  • Fix an issue where a NullPointerException may occur during playback of a video while tracking bandwidth metrics.

v0.4.2

  • Added API method programChange(CustomerVideoData customerVideoData), for use when inside of a single stream the program changes. For instance, in a 24/7 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.
  • Fixed a bug where under poor network conditions, an exception raised as a result of a network request could result in not tracking the view correctly subsequently (such as missing rebuffer tracking after this point).

v0.4.1

  • Remove the listeners on the ExoPlayer object when release is called.
    • This fixes and issue where the application may crash after calling release
      if the ExoPlayer instance is removed while the SDK is still listening to
      it.

v0.4.0

  • [feature] Support bandwidth throughput metrics on video segment download
    for HLS and Dash streaming.
  • breaking change The signature for 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.

v0.3.0

  • breaking change The signature for the MuxStatsExoPlayer constructor
    has changed, and now requires an additional parameter (the first) to be
    and Android Context reference.
  • abstract more core logic into mux-stats-sdk-java
  • [build] rename and copy build artifacts

v0.2.2

  • add back in previously missing methods to MuxStatsExoPlayer:
    • videoChange
    • setPlayerSize
    • error
    • setAutomaticErrorTracking

v0.2.1

  • add support for ExoPlayer r2.7.x
  • add support for ExoPlayer r2.8.x
  • update to v2.1.0 of mux-stats-sdk-java

Updated about a month ago

Integration Guide: ExoPlayer


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.