Skip to content

ExoPlayer Quality Test

Once registered, you can create a Builder for the respective QualityTest which can also be launched in the onCreate method of your activity. In our example we will be using the ExoPlayerQualityTest builder. Have a look at the ExoplayerTestActivity in the demo app for more info.

Warning

Do not instantiate the builder before the registration is complete, as you will receive an exception. Make sure your application is checking the registration before starting the test.

For our ExoPlayerQualityTest, we will play a DASH stream with a known manifest URL. The playback duration is 30 seconds in the below example, and the maximum test duration is a timeout for the test in case of network problems. The analysis duration is a timeout for the actual analysis of the results on the remote server.

Starting the Test

Here is how you can start the test:

ExoPlayerQualityTest mQTest;

ExoPlayerQualityTest.Builder builder = new ExoPlayerQualityTest.Builder(
    this,
    Uri.parse("https://example.com/manifest.mpd")
)
.setMaxPlaybackDuration(30 * 1000)
.setMaxTestDuration(60 * 1000)
.setMaxAnalysisDuration(10 * 1000)
.setResultListener(this)
.setProgressInterval(1000);

try {
    mQTest = builder.build();
    mQTest.start();
} catch (Exception e) {
    Log.e(TAG, "Test start failed", e);
    // Handle exception
}

Builder Options

The ExoPlayerQualityTest.Builder supports the following configuration methods:

  • setMaxPlaybackDuration(long ms) -- maximum playback duration in milliseconds
  • setMaxTestDuration(long ms) -- maximum test duration (timeout) in milliseconds
  • setMaxAnalysisDuration(long ms) -- maximum analysis duration in milliseconds
  • setResultListener(ExoPlayerQualityTestResultListener listener) -- listener for test results, errors, and state changes
  • setProgressInterval(int ms) -- interval for progress callbacks in milliseconds
  • setCalculationSettings(HashMap<String, Object> settings) -- custom calculation settings (e.g., pv and pq model names)
  • setExternalPlayer(ExoPlayer player) -- use an externally created ExoPlayer instance instead of the internal one
  • attachToView(FrameLayout frame) -- attach the player to a view for visual playback during the test
  • setInitialBitrateEstimate(long bps) -- initial bitrate estimate for the bandwidth meter in bits per second. Higher values cause the player to start with higher quality renditions (e.g., 50_000_000 for 50 Mbps).
  • setForceHighestSupportedBitrate(boolean force) -- force the player to always select the highest supported bitrate, bypassing adaptive bitrate selection
  • setIgnoreViewportConstraints(boolean ignore) -- ignore viewport size constraints imposed by the PlayerView. When a PlayerView is attached, ExoPlayer limits track selection to the view's layout dimensions (e.g., a small view may cap selection at 480p). Setting this to true clears those constraints so the ABR algorithm can select higher quality tracks regardless of display size.

Tip

You can get other test URLs from the hls.js demo or the dash.js demo. All of these should work fine with the ExoPlayerQualityTest.

Receiving Test Results

To receive the outcomes of the test, your activity or class must implement the ExoPlayerQualityTestResultListener interface. This interface includes methods for handling successful results, errors, and state changes.

Test Success

When the test completes successfully, the onTestResult method is called:

@Override
public void onTestResult(@NonNull Map<String, Object> result) {
    Log.i(TAG, "Test result received: " + result);
    // Convert the result to a JSON string for display or storage
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String resultJson = gson.toJson(result);
    // Process or display the resultJson
}

The results correspond to the measurement data, so please refer to that page for more information on the values.

Test Errors

If an error occurs during the test, the onTestError method is invoked:

@Override
public void onTestError(@NonNull QualityTestException error) {
    // Handle the error, e.g., display a message to the user
    Log.e(TAG, "Test error: " + error.getMessage(), error);
}

Test State Changes

You can monitor the lifecycle of the test by implementing the onTestStateChanged method from the ExoPlayerQualityTestResultListener interface:

@Override
public void onTestStateChanged(QualityTestState state) {
    Log.d(TAG, "Test state: " + state);
}

Performance Monitoring Datasource

We provide a special loader for ExoPlayer that monitors the performance of each segment request. This is useful for performance monitoring, connection troubleshooting, etc.

To use it, you must instantiate the ExoPlayer yourself (i.e., not use the ExoPlayerQualityTest's internal ExoPlayer instance). Before you instantiate the ExoPlayer itself, call:

import com.aveq.qoereporting.PerformanceMonitoringHttpDataSourceFactory;
import com.aveq.qoereporting.PerformanceMonitoringHttpDataSource.PerformanceListener;

// ...

DefaultHttpDataSource.Factory defaultHttpDataSourceFactory = new DefaultHttpDataSource.Factory();
HttpDataSource.Factory performanceMonitoringFactory =
        new PerformanceMonitoringHttpDataSourceFactory(defaultHttpDataSourceFactory, this);
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(performanceMonitoringFactory);

ExoPlayer mPlayer = new ExoPlayer.Builder(mContext)
    .setMediaSourceFactory(mediaSourceFactory)
    .build();

Then pass that ExoPlayer instance to the ExoPlayerQualityTest builder:

ExoPlayerQualityTest.Builder builder = new ExoPlayerQualityTest.Builder(
    this,
    Uri.parse("https://example.com/manifest.mpd")
)
.setExternalPlayer(mPlayer);

Now make sure your activity implements the PerformanceMonitoringHttpDataSource.PerformanceListener interface:

/**
 * Called when performance metrics are available for a segment request.
 *
 * @param url              The URL of the segment.
 * @param bytesTransferred The number of bytes transferred.
 * @param totalTime        The total time taken to transfer the segment in seconds.
 * @param ttfb             The time to first byte in milliseconds.
 * @param throughput       The throughput in kilobits per second.
 */
@Override
public void onRequestPerformance(String url, long bytesTransferred, double totalTime, long ttfb, double throughput) {
    // Handle the performance data
}

You will receive onRequestPerformance calls for each segment request.

Instrumented Usage

The ExoPlayerQualityTest can be initiated via adb by passing intent extras to the demo ExoplayerTestActivity. This is useful for automated testing scenarios.

adb shell am start -n "com.aveq.qualitytestlibdemo/.ExoplayerTestActivity" \
  --ez autoRunTest true \
  --el maxPlaybackDuration 30000 \
  --el maxTestDuration 45000 \
  --ez displayPlayer true

The following intent extras are supported:

  • autoRunTest (boolean) -- start the test automatically on activity launch
  • maxPlaybackDuration (long) -- max playback duration in ms
  • maxTestDuration (long) -- max test duration in ms
  • manifestUri (string) -- manifest URI to test
  • displayPlayer (boolean) -- show the player view during the test
  • pvModel (string) -- Pv model name
  • pqModel (string) -- Pq model name
  • initialBitrateEstimate (long) -- initial bitrate estimate in bps
  • forceHighestBitrate (boolean) -- force highest supported bitrate
  • ignoreViewportConstraints (boolean) -- ignore viewport size constraints for track selection

We provide a shell script to run the quality test using the above call, which extracts the test results directly from the Android log. See ./run_exoplayer_quality_test.sh for more info.