Skip to content

Commit

Permalink
Merge pull request #35 from StreamAMG/feature/CORE-5217-Bitmovin-anal…
Browse files Browse the repository at this point in the history
…ytics

Feature/core 5217 bitmovin analytics
  • Loading branch information
KharchenkoAlex authored Dec 3, 2024
2 parents 4849f7f + 10f3916 commit f516b99
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class NativeMediaPlayerPlugin : VideoPlayerPlugin {
}

@Composable
override fun PlayerView(hlsUrl: String): Unit {
override fun PlayerView(hlsUrl: String, analyticsViewerId: String?) {
mediaPlayer = MediaPlayer()

val textureView = rememberTextureView()
Expand Down
10 changes: 8 additions & 2 deletions docs/data/tutorials/playbacksdk/getstarted.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
},
{
"type": "text",
"text": "Create an instance of the custom video player plugin and configure it by setting playback options such as autoplay and background playback. To do this, create a `VideoPlayerConfig` object, update its autoplay and background playback settings, and then pass this configuration object to the plugin."
"text": "Create an instance of the custom video player plugin and configure it by setting playback options such as autoplay, background playback, and fullscreen settings. Begin by creating a VideoPlayerConfig object, then update its autoplay, background playback, and fullscreen settings, including enabling fullscreen on screen rotation (fullscreenRotationEnabled) and activating the fullscreen button (fullscreenEnabled). Finally, pass this configuration object to the plugin."
},
{
"type": "text",
Expand Down Expand Up @@ -302,7 +302,7 @@
{
"type": "text",
"text": "The "
},
},
{
"type": "strong",
"inlineContent": [
Expand Down Expand Up @@ -513,6 +513,8 @@
" val playerConfig = VideoPlayerConfig()",
" playerConfig.playbackConfig.autoplayEnabled = true",
" playerConfig.playbackConfig.backgroundPlaybackEnabled = true",
" playerConfig.playbackConfig.fullscreenRotationEnabled = true",
" playerConfig.playbackConfig.fullscreenEnabled = true",
" // Inject the player config to the plugin",
" customPlugin.setup(playerConfig)",
"",
Expand Down Expand Up @@ -665,6 +667,8 @@
" val playerConfig = VideoPlayerConfig()",
" playerConfig.playbackConfig.autoplayEnabled = true",
" playerConfig.playbackConfig.backgroundPlaybackEnabled = true",
" playerConfig.playbackConfig.fullscreenRotationEnabled = true",
" playerConfig.playbackConfig.fullscreenEnabled = true",
" // Inject the player config to the plugin",
" customPlugin.setup(playerConfig)",
"",
Expand Down Expand Up @@ -755,6 +759,8 @@
" val playerConfig = VideoPlayerConfig()",
" playerConfig.playbackConfig.autoplayEnabled = true",
" playerConfig.playbackConfig.backgroundPlaybackEnabled = true",
" playerConfig.playbackConfig.fullscreenRotationEnabled = true",
" playerConfig.playbackConfig.fullscreenEnabled = true",
" // Inject the player config to the plugin",
" customPlugin.setup(playerConfig)",
"",
Expand Down
2 changes: 1 addition & 1 deletion playback-sdk-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ plugins {
}

group = "com.streamamg"
version = "1.0.4"
version = "1.0.5"

subprojects {
apply(plugin = "org.jetbrains.dokka")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ object PlaybackSDKManager {
*/
internal var baseURL = "https://api.playback.streamamg.com/v1"
internal var bitmovinLicense: String = ""
internal var analyticsLicense: String? = null
private var userAgent: String? = null

val playbackSdkVersion = BuildConfig.SDK_VERSION
Expand Down Expand Up @@ -94,17 +95,20 @@ object PlaybackSDKManager {
* Composable function that loads and renders the player UI.
* @param entryID The ID of the entry.
* @param authorizationToken The authorization token.
* @param analyticsViewerId The user's id to be tracked in analytics
* @param onError Callback for handling errors. Default is null.
*/
@Composable
fun loadPlayer(
entryID: String,
authorizationToken: String?,
analyticsViewerId: String? = null,
onError: ((PlaybackAPIError) -> Unit)?
) {
PlaybackUIView(
authorizationToken = authorizationToken,
entryId = entryID,
analyticsViewerId = analyticsViewerId,
userAgent = this.userAgent,
onError = onError
)
Expand Down Expand Up @@ -133,6 +137,9 @@ object PlaybackSDKManager {
}

val bitmovinLicense = playerInfo?.player?.bitmovin?.license
val analyticsLicense = playerInfo?.player?.bitmovin?.integrations?.mux?.envKey

this@PlaybackSDKManager.analyticsLicense = analyticsLicense

this@PlaybackSDKManager.bitmovinLicense = bitmovinLicense ?: run {
completion(null, SDKError.MissingLicense)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.io.IOException
Expand Down Expand Up @@ -80,8 +81,8 @@ internal data class Integrations(

@Serializable
internal data class Mux(
val playerName: String? = null,
val envKey: String? = null
@SerialName("player_name") val playerName: String? = null,
@SerialName("env_key") val envKey: String? = null
)

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface VideoPlayerPlugin {
* @param hlsUrl The HLS URL of the video to be played.
*/
@Composable
fun PlayerView(hlsUrl: String)
fun PlayerView(hlsUrl: String, analyticsViewerId: String?)

/**
* Starts playback of the video.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel
import com.bitmovin.analytics.api.AnalyticsConfig
import com.bitmovin.player.PlayerView
import com.bitmovin.player.api.Player
import com.bitmovin.player.api.PlayerConfig
import com.bitmovin.player.api.ui.FullscreenHandler
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
Expand All @@ -49,6 +51,7 @@ class BitmovinVideoPlayerPlugin : VideoPlayerPlugin, LifecycleCleaner {
override val version: String = "1.0"

private var hlsUrl: String = ""
private var analyticsViewerId: String? = null
private var playerConfig = VideoPlayerConfig()
private var playerBind: Player? = null
private val fullscreen = mutableStateOf(false)
Expand All @@ -61,8 +64,10 @@ class BitmovinVideoPlayerPlugin : VideoPlayerPlugin, LifecycleCleaner {
playerConfig.playbackConfig.fullscreenEnabled = config.playbackConfig.fullscreenEnabled
}



@Composable
override fun PlayerView(hlsUrl: String): Unit {
override fun PlayerView(hlsUrl: String, analyticsViewerId: String?): Unit {
val context = LocalContext.current
val isJetpackCompose = when (context) {
is ComponentActivity -> true
Expand All @@ -74,6 +79,7 @@ class BitmovinVideoPlayerPlugin : VideoPlayerPlugin, LifecycleCleaner {
ViewModelProvider(it)[VideoPlayerViewModel::class.java]
} ?: viewModel()

this.analyticsViewerId = analyticsViewerId
this.hlsUrl = hlsUrl
val currentLifecycle = LocalLifecycleOwner.current
val lastHlsUrl = remember { mutableStateOf(hlsUrl) }
Expand All @@ -91,7 +97,7 @@ class BitmovinVideoPlayerPlugin : VideoPlayerPlugin, LifecycleCleaner {
}

DisposableEffect(hlsUrl) {
playerViewModel?.initializePlayer(context, playerConfig, hlsUrl)
playerViewModel?.initializePlayer(context, playerConfig, hlsUrl, analyticsViewerId)
playerBind = playerViewModel?.player
onDispose {
if (isJetpackCompose) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.viewModelScope
import com.bitmovin.analytics.api.AnalyticsConfig
import com.bitmovin.analytics.api.DefaultMetadata
import com.bitmovin.player.api.Player
import com.bitmovin.player.api.PlayerConfig
import com.bitmovin.player.api.analytics.AnalyticsPlayerConfig
import com.bitmovin.player.api.event.Event
import com.bitmovin.player.api.event.PlayerEvent
import com.bitmovin.player.api.event.on
Expand Down Expand Up @@ -50,14 +53,15 @@ class VideoPlayerViewModel : ViewModel() {
}
}

fun initializePlayer(context: Context, config: VideoPlayerConfig, videoUrl: String) {
fun initializePlayer(context: Context, config: VideoPlayerConfig, videoUrl: String, analyticsViewerId: String? = null) {
this.config = config
backgroundPlaybackEnabled = config.playbackConfig.backgroundPlaybackEnabled
autoplayEnabled = config.playbackConfig.autoplayEnabled
if (player == null) {
val playerConfig =
PlayerConfig(key = PlaybackSDKManager.bitmovinLicense)
player = Player(context, playerConfig)
val analyticsConfig = provideAnalyticsConfig(PlaybackSDKManager.analyticsLicense, analyticsViewerId)
player = Player(context, playerConfig, analyticsConfig)
}
unbindFromService(context)

Expand All @@ -77,6 +81,13 @@ class VideoPlayerViewModel : ViewModel() {
updateBackgroundService(context)
}

private fun provideAnalyticsConfig(license: String? = null, analyticsViewerId: String?): AnalyticsPlayerConfig {
return license?.let {
val config = AnalyticsConfig.Builder(it).build()
AnalyticsPlayerConfig.Enabled(config, DefaultMetadata(customUserId = analyticsViewerId))
} ?: AnalyticsPlayerConfig.Disabled
}

private fun loadVideo(videoUrl: String) {
if (!urlsAreEqualExcludingKs(currentVideoUrl ?: "", videoUrl)) {
val sourceConfig = SourceConfig.fromUrl(videoUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ object PlaybackUIView {
fun PlaybackUIView(
authorizationToken: String?,
entryId: String,
analyticsViewerId: String?,
userAgent: String?,
onError: ((PlaybackAPIError) -> Unit)?
) {
Expand Down Expand Up @@ -59,7 +60,7 @@ object PlaybackUIView {
} else {
videoURL?.let { url ->
VideoPlayerPluginManager.selectedPlugin?.let { plugin ->
plugin.PlayerView(url)
plugin.PlayerView(url, analyticsViewerId)
}
} ?: run {
// TODO: Handle null video URL (Error UI View)
Expand Down

0 comments on commit f516b99

Please sign in to comment.