Android SDK (Core)
Integrate External Player

Integrating ExoPlayer

5min

The external ExoPlayer is now deprecated. We strongly encourage you to switch to our custom player, NwPlayer. Please consult the migration section for detailed instructions on how to migrate from external ExoPlayer to NwPlayer.

We, NativeWaves AG, have designed our SDK to integrate seamlessly with your custom ExoPlayer implementation. By leveraging our observer feature, you can smoothly inject your version of ExoPlayer into the SDK’s playback process, ensuring a tailored experience for your users.

This observer is intelligently designed to activate at key moments, ensuring optimal synchronization with the SDK’s lifecycle and usage scenarios:

  • Initialization: The observer is triggered during the initialization phase of audio or video players, setting the stage for immediate playback needs.
  • Switching Tracks: It also reactivates whenever a switch in video or audio (if applicable) tracks allows dynamic content changes without interrupting the user experience.

Below, we have provided a code snippet to help you understand how to observe the signal and inject your ExoPlayer instance. While this example demonstrates one way to achieve this, feel free to adapt it to fit your application’s architecture and requirements.

Code Breakdown

Here is the provided code snippet:

Kotlin


Let us break it down step by step:

  1. expInitializePlayer: SharedFlow<CompletableDeferred<ExoPlayer>>
    • This is a SharedFlow that emits CompletableDeferred<ExoPlayer> objects. A SharedFlow is a Kotlin coroutine construct that allows multiple collectors to receive the same data stream. In this case, it signals when it is time to initialize and inject your ExoPlayer instance.
    • CompletableDeferred is a special type of Deferred that can be manually completed. It acts as a promise, allowing the SDK to wait for your ExoPlayer instance to be ready before proceeding with playback.
  2. .collect { deferred -> ... }
    • The collect function is used to observe the SharedFlow. Whenever a new CompletableDeferred is emitted, the code inside the collect block is executed.
  3. deferred.complete(generateExoplayer())
    • You generate your custom ExoPlayer instance using the generateExoplayer() function (which you must implement). The complete function is then called on the CompletableDeferred object to provide the SDK with your ExoPlayer instance.
    • The complete function returns a Boolean indicating the operation’s success.
  4. Success and Error Logging (Optional)
    • If the complete operation is successful, a log message is printed using Timber.d to confirm that the ExoPlayer instance was sent successfully.
    • If it fails, an error message is logged using Timber.e to help you debug the issue.

Why Use CompletableDeferred and SharedFlow?

  • CompletableDeferred: This bridges your code and the SDK. It allows the SDK to wait for your ExoPlayer instance to be ready before proceeding, ensuring that playback starts smoothly without timing issues.
  • SharedFlow: This creates a reactive stream that multiple collectors can observe. It ensures the SDK can signal your code at the right moments (e.g., during initialization or stream switches) without tightly coupling your implementation to the SDK’s internal logic.
  • If you do not implement the observer, your event will not use your ExoPlayer; instead, it will run on our SDK's internal player.
  • Be careful when calling the collect {} function. It should be called only once; otherwise, you may experience abnormal behavior while streaming any event.

Conclusion

This mechanism provides a decoupled and flexible way to integrate custom ExoPlayer instances into your application. Using our observer feature, you can enhance our SDK’s video and audio playback capabilities with your tailored solutions, ensuring your users' seamless and personalized experience.