Skip to content

Commit

Permalink
464 fix analytics event skip next or previous media item (#465)
Browse files Browse the repository at this point in the history
Co-authored-by: Gaëtan Muller <[email protected]>
  • Loading branch information
StaehliJ and MGaetan89 authored Mar 12, 2024
1 parent 1671716 commit b40b156
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 16 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ jobs:
build:
name: Build
runs-on: ubuntu-latest
env:
USERNAME: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class CommandersActTrackerIntegrationTest {
}

@Test
fun `audio URN don't send any analytics`() {
fun `audio URN send any analytics`() {
val tcMediaEventSlot = slot<TCMediaEvent>()

player.setMediaItem(MediaItemUrn(URN_AUDIO))
Expand Down Expand Up @@ -572,6 +572,41 @@ class CommandersActTrackerIntegrationTest {
confirmVerified(commandersAct)
}

@Test
fun `player seek to next item doesn't send seek event`() {
val tcMediaEvents = mutableListOf<TCMediaEvent>()
player.addMediaItem(MediaItemUrn(URN_NOT_LIVE_VIDEO))
player.addMediaItem(MediaItemUrn(URN_VOD_SHORT))
player.prepare()
player.play()

TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY)
TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player)
player.seekToNextMediaItem()

TestPlayerRunHelper.runUntilTimelineChanged(player)
TestPlayerRunHelper.playUntilStartOfMediaItem(player, 1)
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED)
TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player)

verifyOrder {
commandersAct.enableRunningInBackground()
commandersAct.sendTcMediaEvent(capture(tcMediaEvents))
commandersAct.sendTcMediaEvent(capture(tcMediaEvents))

commandersAct.enableRunningInBackground()
commandersAct.sendTcMediaEvent(capture(tcMediaEvents))
commandersAct.sendTcMediaEvent(capture(tcMediaEvents))
}
confirmVerified(commandersAct)

assertEquals(4, tcMediaEvents.size)

assertEquals(listOf(Play, Stop, Play, Eof).reversed(), tcMediaEvents.map { it.eventType })
assertTrue(tcMediaEvents.all { it.assets.isNotEmpty() })
assertTrue(tcMediaEvents.all { it.sourceId == null })
}

@Test
fun `player prepared and stopped`() {
player.setMediaItem(MediaItemUrn(URN_LIVE_VIDEO))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ package ch.srgssr.pillarbox.player.tracker
import androidx.annotation.VisibleForTesting
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.common.Timeline
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.analytics.AnalyticsListener
import ch.srgssr.pillarbox.player.extension.getMediaItemTrackerData
import ch.srgssr.pillarbox.player.extension.getMediaItemTrackerDataOrNull

Expand All @@ -28,7 +28,7 @@ import ch.srgssr.pillarbox.player.extension.getMediaItemTrackerDataOrNull
internal class CurrentMediaItemTracker internal constructor(
private val player: ExoPlayer,
private val mediaItemTrackerProvider: MediaItemTrackerProvider
) : Player.Listener {
) : AnalyticsListener {

/**
* Trackers are null if tracking session is stopped!
Expand All @@ -49,7 +49,7 @@ internal class CurrentMediaItemTracker internal constructor(
}

init {
player.addListener(this)
player.addAnalyticsListener(this)
player.currentMediaItem?.let { startNewSession(it) }
}

Expand Down Expand Up @@ -126,11 +126,11 @@ internal class CurrentMediaItemTracker internal constructor(
}
}

override fun onTimelineChanged(timeline: Timeline, reason: Int) {
override fun onTimelineChanged(eventTime: AnalyticsListener.EventTime, reason: Int) {
setMediaItem(player.currentMediaItem)
}

override fun onPlaybackStateChanged(playbackState: Int) {
override fun onPlaybackStateChanged(eventTime: AnalyticsListener.EventTime, playbackState: Int) {
when (playbackState) {
Player.STATE_ENDED -> stopSession(MediaItemTracker.StopReason.EoF)
Player.STATE_IDLE -> stopSession(MediaItemTracker.StopReason.Stop)
Expand All @@ -141,24 +141,25 @@ internal class CurrentMediaItemTracker internal constructor(
}
}

override fun onPositionDiscontinuity(oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, reason: Int) {
override fun onPositionDiscontinuity(
eventTime: AnalyticsListener.EventTime,
oldPosition: Player.PositionInfo,
newPosition: Player.PositionInfo,
reason: Int
) {
val oldPositionMs = oldPosition.positionMs
when (reason) {
Player.DISCONTINUITY_REASON_REMOVE -> stopSession(MediaItemTracker.StopReason.Stop, oldPositionMs)
Player.DISCONTINUITY_REASON_AUTO_TRANSITION -> stopSession(MediaItemTracker.StopReason.EoF, oldPositionMs)
else -> {
// Nothing
if (oldPosition.mediaItemIndex != newPosition.mediaItemIndex) {
stopSession(MediaItemTracker.StopReason.Stop, oldPositionMs)
}
}
}
}

/**
* On media item transition
*
* @param mediaItem maybe null when playlist become empty
* @param reason
*/
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
override fun onMediaItemTransition(eventTime: AnalyticsListener.EventTime, mediaItem: MediaItem?, reason: Int) {
setMediaItem(player.currentMediaItem)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,45 @@ class MediaItemTrackerTest {
confirmVerified(fakeMediaItemTracker)
}

@Test
fun `playlist skip next stop current tracker`() {
val firstMediaId = FakeMediaItemSource.MEDIA_ID_1
val secondMediaId = FakeMediaItemSource.MEDIA_ID_2
player.apply {
addMediaItem(
MediaItem.Builder()
.setMediaId(firstMediaId)
.build()
)
addMediaItem(
MediaItem.Builder()
.setMediaId(secondMediaId)
.build()
)
prepare()
play()
}
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY)

RobolectricUtil.runMainLooperUntil {
val item = player.currentMediaItem
item?.getMediaItemTrackerDataOrNull() != null
}

player.seekToNextMediaItem()

TestPlayerRunHelper.runUntilTimelineChanged(player)

TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled(player)

verifyOrder {
fakeMediaItemTracker.start(player, FakeMediaItemTracker.Data(firstMediaId))
fakeMediaItemTracker.stop(player, MediaItemTracker.StopReason.Stop, any())
fakeMediaItemTracker.start(player, FakeMediaItemTracker.Data(secondMediaId))
}
confirmVerified(fakeMediaItemTracker)
}

@Test
fun `playlist repeat current item reset current tracker`() {
val firstMediaId = FakeMediaItemSource.MEDIA_ID_1
Expand All @@ -637,7 +676,6 @@ class MediaItemTrackerTest {
fakeMediaItemTracker.start(any(), FakeMediaItemTracker.Data(firstMediaId))
fakeMediaItemTracker.stop(any(), MediaItemTracker.StopReason.EoF, any())
fakeMediaItemTracker.start(any(), FakeMediaItemTracker.Data(firstMediaId))
// player.stop
fakeMediaItemTracker.stop(any(), MediaItemTracker.StopReason.Stop, any())
}
confirmVerified(fakeMediaItemTracker)
Expand Down

0 comments on commit b40b156

Please sign in to comment.