Android SDK (Core)
Integrate External Player
Integrating NwPlayer
9 min
we allow you to integrate your preferred media player into our sdk using the nwplayer interface this approach, introduced in sdk version 4 10 0 or later , is the recommended and future proof solution for external player integration unlike the deprecated exoplayer injection method, nwplayer gives you full control over the player, allowing you to customize its behavior and even use players other than exoplayer below, we provide a high level overview of integrating your custom player using the nwplayer interface for detailed implementation steps, refer to this documentation's code examples and explanations key features of nwplayer full control you can customize the player's behavior, including playback, buffering, and error handling flexibility you can wrap any player (e g , exoplayer, mediaplayer, or a custom player) and integrate it into the sdk lifecycle management you are responsible for handling the player's lifecycle, including methods like resume, pause, seekto, and release caution required since you have complete control, ensure the player responds correctly to the sdk's calls to avoid playback issues implementation with an example below is a simplified example of how to implement the nwplayer interface using exoplayer class externalnwplayer(private val context context) nwplayer, player listener { private lateinit var exoplayer exoplayer override var bitrate long = 0l, // do not assign or modify later override lateinit var playbackobject playbackobject // do not assign or modify override lateinit var playerlistener nwplayerlistener // do not assign or modify override fun prepare() { exoplayer = exoplayer builder(context) build() exoplayer setmediasource(buildmediasource()) exoplayer prepare() playerlistener onprepared(this) } override fun resume() { exoplayer playwhenready = true } override fun pause() { exoplayer playwhenready = false } override fun seekto(offsetms long) { exoplayer seekto(offsetms) } override fun stop() { exoplayer stop() } override fun release() { exoplayer release() } override fun onplaywhenreadychanged(playwhenready boolean, reason int) { playerlistener onstatechange(playbackobject, playwhenready) } // other methods and properties } how to inject nwplayer to the sdk below, we have provided a code snippet to help you understand how to observe the signal and inject your nwplayer instance while this example demonstrates one way to achieve this, feel free to adapt it to fit your application’s architecture and requirements here is the provided code snippet expplayback externalnwplayer collect { deferred > val success = deferred complete(externalnwplayer(context)) if (success) { log d("sampleapp", "successfully sent nwplayer instance") } else { log e("sampleapp", "failed to send nwplayer instance") } } let us break it down step by step expinitializeplayer sharedflow\<completabledeferred\<nwplayer>> this is a sharedflow that emits completabledeferred\<nwplayer> 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 nwplayer 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 nwplayer instance to be ready before proceeding with playback 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 deferred complete(externalnwplayer(context)) you generate your custom nwplayer instance using the externalnwplayer(context) function (which you must implement) the complete function is then called on the completabledeferred object to provide the sdk with your nwplayer instance the complete function returns a boolean indicating the operation’s success success and error logging (optional) if the complete operation is successful, a log message is printed using timber d to confirm that the nwplayer 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 nwplayer 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 nwplayer ; 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 important properties managed by the sdk when implementing the nwplayer interface in your custom class (e g , externalnwplayer), three critical properties should not be assigned or modified directly within your implementation the sdk manages these properties exclusively, and any attempt to set or modify their values may lead to unexpected behavior or issues override var bitrate long = 0l purpose represents the current bitrate of the media stream managed by the sdk automatically updates this value based on the media stream’s bandwidth and quality caution do not assign or modify this value in your custom class you cannot use lateinit modifier as it is not allowed on properties of primitive types override lateinit var playbackobject playbackobject purpose contains metadata, urls, drm configurations, and other details about the media to be played managed by the sdk initializes and assigns this object when preparing the player caution do not assign or modify this object in your custom class override lateinit var playerlistener nwplayerlistener purpose a listener communicating player events (e g , buffering, errors, state changes) to the sdk managed by the sdk assigns this listener to handle player events caution do not assign or modify this listener in your custom class why should you avoid assigning these properties? unexpected behavior the sdk relies on these properties to manage playback, track bitrate, and handle events assigning or modifying them directly can disrupt the sdk’s functionality lifecycle issues these properties are initialized and managed at specific sdk lifecycle points interfering with them can lead to crashes or playback failures event handling the playerlistener is used to communicate critical events to the sdk reassigning it can break event propagation and lead to unresponsive playback here is how these properties should be used in your custom class class externalnwplayer(private val context context) nwplayer { override var bitrate long = 0l, // do not assign or modify override lateinit var playbackobject playbackobject // do not assign or modify override lateinit var playerlistener nwplayerlistener // do not assign or modify // your implementation } in this example, the properties are declared but not assigned or modified within the class the sdk will handle their initialization and updates always remember that the sdk manages bitrate , playbackobject , and playerlistener avoid assigning or modifying these properties in your custom class to ensure smooth and error free playback if you encounter issues, double check that these properties are not being interfered with in your implementation