Skip to content

Manual Player Integration

If you choose to use the manual integration, some player metrics are required to be reported to the SDK to ensure its proper functionality. Please find below the required metrics and the instructions on how to report them to the SDK.

Providing player details

After initializing the SDK instance, you can report the name and version of the player you are using as shown below.

    // Name and version of the player you are using
    polyNet.reportPlayerName(<PLAYER_NAME>); 
    polyNet.reportPlayerVersion(<PLAYER_VERSION>);

    // For example:
    // polyNet.reportPlayerName("exoplayer");
    // polyNet.reportPlayerVersion(ExoPlayerLibraryInfo.VERSION);

Providing metrics

You MUST provide the SDK instance with some of the video player's metrics. For each reported metric, call the specific report method of the SDK instance as explained below.

For the Edge Intelligence SDK to work properly you MUST provide regularly the buffer health metric.

Each video player provides access to the metrics in different ways.

  • Some players notify periodically the subscribed listeners.

  • Some player's metrics may be obtained at any time.

Our System73 Edge Intelligence SDK instance supports both ways:

  • You are free to report a metric at the moment it is reported by the player. For example, ExoPlayer requires you to implement the AnalyticsListener interface, and it will call its onDroppedVideoFrames, onPlaybackStateChanged, onSurfaceSizeChanged and onVideoSizeChanged callbacks, as in the following code snippet. You should setup ExoPlayer to immediately report every single dropped frame.
player.addAnalyticsListener(new AnalyticsListener() {
   @Override
   public void onPlaybackStateChanged(EventTime eventTime, int state) {
      if (state == Player.STATE_READY) {
         if (polyNet != null) {
            polyNet.reportPlayBackStarted();
         }
      }
   }

   @Override
   public void onDroppedVideoFrames(EventTime eventTime, int count, long elapsed) {
      for (int n = 0; n < count; n++) {
         if (polyNet != null) {
            polyNet.reportDroppedFrame();
         }
      }
   }

   @Override 
   public void onSurfaceSizeChanged(EventTime eventTime, int width, int height) {
       polyNet.reportViewportSize(width, height);
   }

   @Override 
   public void onVideoSizeChanged(EventTime eventTime, VideoSize videoSize) {
       polyNet.reportVideoResolution(videoSize.width, videoSize.height);
   }

});

In our Sample App using ExoPlayer 2, this source code is inside the PlayerActivity class.

  • The SDK instance requests each metric asynchronously using the PolyNetPlayerListener instance assigned in the initialisation steps. The metric can be reported directly from the callback, or when it is possible to fetch it from the player's instance.

  • If it is not possible to get a metric from the player, don't call the specific report method for that metric. In case that buffer health is not provided, the following WARNING message will be displayed in console log five times at most: Buffer health not provided. This might cause QoE issues.

In the following example, you can see that the buffer health and the player state can be obtained from the player, but the other metrics are not available:

polyNet.setPlayerListener(new PolyNetPlayerListener() {
        @Override
        public void onBufferHealthRequest(PolyNet polyNet) {
            runOnUiThread(() -> {
                if (player != null) {
                    // Report the buffer health only if we can compute it
                    long bufferHealthInMs = player.getTotalBufferedDuration();
                    polyNet.reportBufferHealth(bufferHealthInMs);
                }
            });
        }        

        @Override
        public void onPlayerStateRequest(PolyNet polyNet, final PlayerState oldPlayerState) {
            runOnUiThread(() -> {
                if (player != null) {
                    boolean isPlaying = player.isPlaying();
                     // For ExoPlayer < 2.12
                     // boolean isPlaying = player.getPlaybackState() == Player.STATE_READY 
                     //         && player.getPlayWhenReady(); 
                    int playbackState = player.getPlaybackState();
                    PlayerState currentPlayerState;

                    if ((oldPlayerState == PlayerState.UNKNOWN || oldPlayerState == PlayerState.STARTING) 
                            && playbackState == Player.STATE_BUFFERING) {
                        currentPlayerState = PlayerState.STARTING;
                    } else if (isPlaying) {
                        currentPlayerState = PlayerState.PLAYING;
                    } else if (playbackState == Player.STATE_BUFFERING) {
                        currentPlayerState = PlayerState.BUFFERING;
                    } else if (playbackState == Player.STATE_READY) {
                        currentPlayerState = PlayerState.PAUSE;
                    } else {
                        currentPlayerState = PlayerState.UNKNOWN;
                    }

                    polyNet.reportPlayerState(currentPlayerState);
                }
            });
        }

        @Override
        public void onDroppedFramesRequest(PolyNet polyNet) {
            // No need to implement it for ExoPlayer.
        }

        @Override
        public void onPlayBackStartedRequest(PolyNet polyNet) {
            // No need to implement it for ExoPlayer.
        }
});

This source code for integrating the SDK and passing the the player manually to the SDK is shown in the PlayerActivity class of the System73 Sample App (check out the method integratePlayerManually())

Note

In the source code of the PlayerActivity class, by default integratePlayerUsingPlugin() is used and integratePlayerManually() is commented out. To use the manual integration as shown in this page, uncomment integratePlayerManually() and comment out integratePlayerUsingPlugin().

Note

To ensure ExoPlayer functions optimally and provides accurate feedback, it's necessary to implement the AnalyticsListener interface. This interface facilitates communication between ExoPlayer and your application, allowing it to relay important events such as onDroppedVideoFrames, onPlaybackStateChanged, onSurfaceSizeChanged and onVideoSizeChanged callbacks. The AnalyticsListener is part of the androidx.media3.exoplayer.analytics package. Although omitting this implementation might not immediately cause errors, it can result in misleading feedback or indications within the application. However, it's important to note that the application will continue to function normally even without this implementation.

Adding @UnstableApi will suppress the error indication.

player.addAnalyticsListener(new AnalyticsListener() {
            @UnstableApi
            @Override
            public void onPlaybackStateChanged(EventTime eventTime, int state) {
                if (state == Player.STATE_READY) {
                    if (polyNet != null) {
                        polyNet.reportPlayBackStarted();
                    }
                }
            }

            @UnstableApi
            @Override
            public void onDroppedVideoFrames(EventTime eventTime, int count, long elapsed) {
                for (int n = 0; n < count; n++) {
                    if (polyNet != null) {
                        polyNet.reportDroppedFrame();
                    }
                }
            }

            @UnstableApi
            @Override
            public void onSurfaceSizeChanged(EventTime eventTime, int width, int height) {
                polyNet.reportViewportSize(width, height);
            }

            @UnstableApi
            @Override
            public void onVideoSizeChanged(EventTime eventTime, VideoSize videoSize) {
                polyNet.reportVideoResolution(videoSize.width, videoSize.height);
            }

        });

This section was last updated 2024-12-19