Skip to content

Latest commit

 

History

History
273 lines (231 loc) · 8.19 KB

README.md

File metadata and controls

273 lines (231 loc) · 8.19 KB

AVVPlayer-MARVIN-Android

Links

Developer Guide

Basic Integration

Adding AVVPL to your project

1. Add the maven repository to your project level build.gradle

allprojects {
    repositories {
        ...
        maven { url "https://avvpl-staging.sportradar.com/dist/android/latest/" }
        maven { url 'http://bitmovin.bintray.com/maven' }
        ...
    }
}

KNOWN ISSUE: Bitmovin Analytics integration demands adding the bitmovin maven repository. Fixing this issue is in progress.

2. Add the avvpl dependency to your app module build.gradle

implementation("ag.sportradar.android:avvplayermarvin:X.X.X")

The newest Version can be found here

Checking for a valid licence

    val licence = AVVLicence.Builder(this, "[your_licence_key]")
                .domain("[www.yourlicencedomain.com]") //if required
                .bundle("[com.your.appid]") //optional: it will pick the applictiationId per default 
                .listener(object : AVVLicenceCheckListener {
                    override fun onLicenceValidated(valid: Boolean) {
                        // player should not be built before licence is validated.
                    }
                })
                .build()

    AVVSettings.instance.checkLicence(licence)

Creating the AVVPlayer instance

1. Instantiate the Player

val player = AVVPlayerBuilder(context) //your Activity's context
            .setPlayerContainer(playerContainer) //the viewgroup that contains the player
            .build()

2. Start the video passing a video configuration to the player

player.setup(AVVConfigUrl("[URL to the OTT videoconfig]"))

or

player.setup(AVVStreamUrl("https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8"))

or

player.setup(AVVConfig.Builder(0)
                    .streamUrl("https://cdn.theoplayer.com/video/elephants-dream/playlist.m3u8")
                    .build())

Handle lifecycle events

The AVVPlayer instance needs to react to certain lifecycle events of the application, such as onPause(), onResume() and onDestroy().

class MainActivity : AppCompatActivity() {
    override fun onPause() {
        player.onActivityPause()
        super.onPause()
    }
 
    override fun onResume() {
        player.onActivityResume()
        super.onResume()
    }
 
    override fun onDestroy() {
        player.onActivityDestroy()
        super.onDestroy()
    }
}

POSSIBLE ISSUE: player.onActivityDestroy() calls Exoplayers stop() and release() method. As release() is known for blocking the UI Thread until all resources are released,some devices (especially lowend devices) might appear to freeze for 1-3 seconds. If you are experiencing these issues try calling

player.onActivityDestroy(killPlaybackThread = false)

instead.

Handle orientation change

In order for the AVVPlayer to continue playback through orientation changes you need to enable configChanges in the Activity that holds the player.

1. Add the following line to your activity in the AndroidManifest.xml

<activity 
    android:name=".YourPlayerActivity"
    android:configChanges="orientation|screenSize|screenLayout">
    ... 
</activity>

2. Override onConfigurationChanged in your Activity/Fragment that holds the player

override fun onConfigurationChanged(newConfig: Configuration) {
        player.onConfigurationChanged(newConfig)
        super.onConfigurationChanged(newConfig)
    }

Changing the player configuration (if required)

The player fetches its configuration from the URL that is passed in the setUp() call. The configuration determines the looks and the behavior of the player, however if you wish to change any of this behavior or need to add necessary information to the player configuration you can do so by implementing AVVConfigAdaptationCallback and adding it to the player.setup() call

player.setup(config, object : AVVConfigAdaptationCallback() {})
  • Adding request headers to streamaccess
player.setUp(config, object : AVVConfigAdaptationCallback() {
            override fun adaptConfig(config: AVVConfig) {
                //...
                config.streamUrlProviderInfo.requestData = AVVPostRequestData(mapOf(Pair("authorization", "your auth token")))
                //...
            }
})
  • Changing autoplay behavior
player.setUp(config, object : AVVConfigAdaptationCallback() {
             
            override fun adaptConfig(config: AVVConfig) {
                //...
                config.playbackOptions.autoPlay = true
                //...
            }
             
        })
  • Add heartbeat
player.setUp(config, object : AVVConfigAdaptationCallback() {
             
            override fun adaptConfig(config: AVVConfig) {
                //...
                config.heartbeat = AVVHeartbeat.Builder()
                    .enabled(true)
                    .time(30) //seconds
                    .ticket("[your heartbeat ticket]")
                    .validationPath("https://yourvalidation.com/validation")
                    .build()
                    
                 //...
            }
             
        })

Customizing UI

Customize Error Overlay

class MyErrorOverlay : AVVErrorOverlayDelegate {
    override fun onCreateErrorView(parent: ViewGroup, error: AVVError): View {
        val layoutInflater = LayoutInflater.from(parent.context)
        val view = layoutInflater.inflate(R.layout.my_error_layout, parent, false)
 
        // display the error data contained in the AVVError as you like.
        return view
    }
}
val player = AVVPlayerBuilder(activity)
            .setPlayerContainer(playerContainer)
            .setCustomErrorOverlay(MyErrorOverlay())
            .build()

Customize Control Overlay

class MyCustomControls : AVVControlOverlayDelegate {
    override fun onCreateErrorView(parent: ViewGroup, error: AVVError): View {
        val layoutInflater = LayoutInflater.from(parent.context)
        val view = layoutInflater.inflate(R.layout.layout_videoplayer_controls, parent, false)
 
         controlBinding.bindPlayPauseButton(
            view.findViewById(R.id.playPauseButton),
            R.drawable.ic_avv_play,
            R.drawable.ic_avv_pause, config.skin
        )

        controlBinding.bindFullscreenButton(
            view.findViewById(R.id.fullscreenButton),
            R.drawable.ic_avv_fullscreen_enter,
            R.drawable.ic_avv_fullscreen_exit
        )

        controlBinding.bindLiveIndicatorView(
            view.findViewById(R.id.liveindicator),
            R.drawable.ic_avv_live_indicator,
            config.skin
        )
 
        // for more bindings check MyCustomControls.kt in DemoApplication
        return view
    }
}
val player = AVVPlayerBuilder(activity)
            .setPlayerContainer(playerContainer)
            .setControlOverlay(MyCustomControls())
            .build()

Chromecast

Create CastOptionsProvider

class DemoCastOptionsProvider: AVVCastOptionsProvider() {
    override fun getReceiverApplicationId(context: Context): String {
        return "YOUR_CAST_RECEIVER_ID"
    }
}

Add the CastOptionsProvider to your AndroidManifest.xml

    <application>
        <meta-data
            android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
            android:value="path.to.your.AVVCastOptionsProvider"
            tools:replace="android:value" />
 
    </application>

Initiate CastContext

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
        //...
        CastContext.getSharedInstance(this)
        //...
    }
    }

(Optional) Add a MiniController to your layout

    <fragment
        android:id="@+id/miniControllerFragment"
        class="ag.sportradar.avvplayer.player.chromecast.widgets.AVVDefaultCastMiniController"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />