From c72fe5eeee5ba32a9e5fb83fcc83b1bb6f860b98 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 23 Aug 2024 15:12:59 +0200 Subject: [PATCH 1/5] merge PlaybackInfoProvider and PlayerHelper into PlayerAdapter --- .../conviva/BitmovinPlayerHelper.java | 31 --- .../conviva/ConvivaAnalyticsIntegration.java | 225 +++++++++--------- .../conviva/DefaultPlayerAdapter.java | 109 +++++++++ .../analytics/conviva/PlayerAdapter.java | 32 +++ .../conviva/helper/WithEventEmitter.java | 8 + .../ssai/DefaultPlaybackInfoProvider.java | 47 ---- .../conviva/ssai/DefaultSsaiApi.java | 11 +- .../conviva/ssai/PlaybackInfoProvider.java | 11 - .../conviva/ssai/DefaultSsaiApiTest.kt | 15 +- 9 files changed, 269 insertions(+), 220 deletions(-) delete mode 100644 conviva/src/main/java/com/bitmovin/analytics/conviva/BitmovinPlayerHelper.java create mode 100644 conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java create mode 100644 conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java create mode 100644 conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java delete mode 100644 conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultPlaybackInfoProvider.java delete mode 100644 conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/PlaybackInfoProvider.java diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/BitmovinPlayerHelper.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/BitmovinPlayerHelper.java deleted file mode 100644 index c1c4b6e..0000000 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/BitmovinPlayerHelper.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bitmovin.analytics.conviva; - -import com.bitmovin.player.api.Player; - -class BitmovinPlayerHelper { - private final Player player; - - BitmovinPlayerHelper(Player player) { - this.player = player; - } - - String getSdkVersionString() { - return Player.getSdkVersion(); - } - - String getStreamType() { - if (player.getSource() == null) { - return null; - } else { - return player.getSource().getConfig().getType().name(); - } - } - - String getStreamUrl() { - if (player.getSource() == null) { - return null; - } else { - return player.getSource().getConfig().getUrl(); - } - } -} diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java index 2c5d86f..4e35bd8 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java @@ -4,9 +4,9 @@ import android.os.Handler; import android.util.Log; -import com.bitmovin.analytics.conviva.ssai.DefaultPlaybackInfoProvider; +import androidx.annotation.NonNull; + import com.bitmovin.analytics.conviva.ssai.DefaultSsaiApi; -import com.bitmovin.analytics.conviva.ssai.PlaybackInfoProvider; import com.bitmovin.analytics.conviva.ssai.SsaiApi; import com.bitmovin.player.api.Player; import com.bitmovin.player.api.advertising.Ad; @@ -36,18 +36,14 @@ public class ConvivaAnalyticsIntegration { private static final String TAG = "ConvivaAnalyticsInt"; - private final Player bitmovinPlayer; private final ContentMetadataBuilder contentMetadataBuilder = new ContentMetadataBuilder(); private final ConvivaVideoAnalytics convivaVideoAnalytics; private final ConvivaAdAnalytics convivaAdAnalytics; - private final PlaybackInfoProvider playbackInfoProvider; + @NonNull + private final PlayerAdapter playerAdapter; private MetadataOverrides metadataOverrides; private final DefaultSsaiApi ssai; - - // Wrapper to extract bitmovinPlayer helper methods - private final BitmovinPlayerHelper playerHelper; - // Helper private Boolean isSessionActive = false; private Boolean isBumper = false; @@ -94,8 +90,7 @@ public ConvivaAnalyticsIntegration(Player player, ConvivaAdAnalytics adAnalytics, DefaultSsaiApi ssai ) { - this.bitmovinPlayer = player; - this.playerHelper = new BitmovinPlayerHelper(player); + playerAdapter = new DefaultPlayerAdapter(player); Map settings = new HashMap<>(); if (config.getGatewayUrl() != null || config.isDebugLoggingEnabled()) { if (config.getGatewayUrl() != null) { @@ -117,10 +112,9 @@ public ConvivaAnalyticsIntegration(Player player, } else { convivaAdAnalytics = adAnalytics; } - playbackInfoProvider = new DefaultPlaybackInfoProvider(player); if (ssai == null) { - this.ssai = new DefaultSsaiApi(convivaVideoAnalytics, convivaAdAnalytics, playbackInfoProvider); + this.ssai = new DefaultSsaiApi(convivaVideoAnalytics, convivaAdAnalytics, playerAdapter); } else { this.ssai = ssai; } @@ -134,7 +128,7 @@ private void setUpAdAnalyticsCallback() { @Override public void update() { if (isAdActive()) { - convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, ((long) (bitmovinPlayer.getCurrentTime() * 1000))); + convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, ((long) (playerAdapter.getPlayHeadTimeMillis()))); } } @@ -145,7 +139,7 @@ public void update(String s) { } private boolean isAdActive() { - return bitmovinPlayer.isAd() || ssai.isAdBreakActive(); + return playerAdapter.isAd() || ssai.isAdBreakActive(); } // region public methods @@ -182,7 +176,7 @@ public void sendCustomPlaybackEvent(String name, Map attributes) * If no source was loaded this method will throw an error. */ public void initializeSession() throws ConvivaAnalyticsException { - if ((bitmovinPlayer.getSource() == null || bitmovinPlayer.getSource().getConfig().getTitle() == null) + if ((playerAdapter.getStreamTitle() == null) && this.contentMetadataBuilder.getAssetName() == null) { throw new ConvivaAnalyticsException( "AssetName is missing. Load player source (with Title) first or set assetName via updateContentMetadata" @@ -327,7 +321,7 @@ private void setupPlayerStateManager() { convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, ConvivaSdkConstants.PlayerState.STOPPED); Map playerInfo = new HashMap<>(); playerInfo.put(ConvivaSdkConstants.FRAMEWORK_NAME, "Bitmovin Player Android"); - playerInfo.put(ConvivaSdkConstants.FRAMEWORK_VERSION, playerHelper.getSdkVersionString()); + playerInfo.put(ConvivaSdkConstants.FRAMEWORK_VERSION, Player.getSdkVersion()); convivaVideoAnalytics.setPlayerInfo(playerInfo); convivaAdAnalytics.setAdPlayerInfo(playerInfo); } @@ -356,7 +350,7 @@ private void updateSession() { } private void updatePlaybackVideoData() { - HashMap playbackVideoData = playbackInfoProvider.getPlaybackVideoData(); + HashMap playbackVideoData = playerAdapter.getPlaybackVideoData(); for (Map.Entry entry : playbackVideoData.entrySet()) { convivaVideoAnalytics.reportPlaybackMetric(entry.getKey(), entry.getValue()); if (ssai.isAdBreakActive()) { @@ -366,14 +360,18 @@ private void updatePlaybackVideoData() { } private void createContentMetadata() { - Source source = bitmovinPlayer.getSource(); - if (source != null) { - SourceConfig sourceConfig = source.getConfig(); - String overriddenAssetName = metadataOverrides != null ? metadataOverrides.getAssetName() : null; - - contentMetadataBuilder.setAssetName(overriddenAssetName != null ? overriddenAssetName : sourceConfig.getTitle()); + String overriddenAssetName = metadataOverrides != null ? metadataOverrides.getAssetName() : null; + if (overriddenAssetName != null) { + contentMetadataBuilder.setAssetName(overriddenAssetName); + } else { + if (playerAdapter.getStreamTitle() != null) { + contentMetadataBuilder.setAssetName(playerAdapter.getStreamTitle()); + } else { + Log.w(TAG, "No asset name provided for content metadata."); + } } - this.buildDynamicContentMetadata(); + + buildDynamicContentMetadata(); } private void buildDynamicContentMetadata() { @@ -381,18 +379,18 @@ private void buildDynamicContentMetadata() { // streamType could be missing at time of session initialization // as source information could be unavailable at that time Map customInternTags = new HashMap<>(); - customInternTags.put(STREAM_TYPE, playerHelper.getStreamType()); + customInternTags.put(STREAM_TYPE, playerAdapter.getStreamType()); customInternTags.put(INTEGRATION_VERSION, BuildConfig.VERSION_NAME); contentMetadataBuilder.setCustom(customInternTags); - if (bitmovinPlayer.isLive()) { + if (playerAdapter.isLive()) { contentMetadataBuilder.setStreamType(ConvivaSdkConstants.StreamType.LIVE); } else { contentMetadataBuilder.setStreamType(ConvivaSdkConstants.StreamType.VOD); - contentMetadataBuilder.setDuration((int) bitmovinPlayer.getDuration()); + contentMetadataBuilder.setDuration((int) playerAdapter.getDuration()); } - contentMetadataBuilder.setStreamUrl(playerHelper.getStreamUrl()); + contentMetadataBuilder.setStreamUrl(playerAdapter.getStreamUrl()); } private void internalEndSession() { @@ -408,80 +406,83 @@ private void internalEndSession() { // endregion private void attachBitmovinEventListeners() { - bitmovinPlayer.on(SourceEvent.Unloaded.class, onSourceUnloadedListener); - bitmovinPlayer.on(PlayerEvent.Error.class, onPlayerErrorListener); - bitmovinPlayer.on(SourceEvent.Error.class, onSourceErrorListener); - bitmovinPlayer.on(PlayerEvent.Warning.class, onPlayerWarningListener); - bitmovinPlayer.on(SourceEvent.Warning.class, onSourceWarningListener); - - bitmovinPlayer.on(PlayerEvent.Muted.class, onMutedListener); - bitmovinPlayer.on(PlayerEvent.Unmuted.class, onUnmutedListener); - - // Playback state events - bitmovinPlayer.on(PlayerEvent.Play.class, onPlayListener); - bitmovinPlayer.on(PlayerEvent.Playing.class, onPlayingListener); - bitmovinPlayer.on(PlayerEvent.Paused.class, onPausedListener); - bitmovinPlayer.on(PlayerEvent.StallEnded.class, onStallEndedListener); - bitmovinPlayer.on(PlayerEvent.StallStarted.class, onStallStartedListener); - bitmovinPlayer.on(PlayerEvent.PlaybackFinished.class, onPlaybackFinishedListener); - - // Seek events - bitmovinPlayer.on(PlayerEvent.Seeked.class, onSeekedListener); - bitmovinPlayer.on(PlayerEvent.Seek.class, onSeekListener); - - // Timeshift events - bitmovinPlayer.on(PlayerEvent.TimeShift.class, onTimeShiftListener); - bitmovinPlayer.on(PlayerEvent.TimeShifted.class, onTimeShiftedListener); - - // Ad events - bitmovinPlayer.on(PlayerEvent.AdBreakStarted.class, onAdBreakStarted); - bitmovinPlayer.on(PlayerEvent.AdBreakFinished.class, onAdBreakFinished); - bitmovinPlayer.on(PlayerEvent.AdStarted.class, onAdStartedListener); - bitmovinPlayer.on(PlayerEvent.AdFinished.class, onAdFinishedListener); - bitmovinPlayer.on(PlayerEvent.AdSkipped.class, onAdSkippedListener); - bitmovinPlayer.on(PlayerEvent.AdError.class, onAdErrorListener); - bitmovinPlayer.on(PlayerEvent.TimeChanged.class, onTimeChangedListener); - - bitmovinPlayer.on(PlayerEvent.VideoPlaybackQualityChanged.class, onVideoPlaybackQualityChangedListener); + playerAdapter.withEventEmitter(eventEmitter -> { + eventEmitter.on(SourceEvent.Unloaded.class, onSourceUnloadedListener); + eventEmitter.on(PlayerEvent.Error.class, onPlayerErrorListener); + eventEmitter.on(SourceEvent.Error.class, onSourceErrorListener); + eventEmitter.on(PlayerEvent.Warning.class, onPlayerWarningListener); + eventEmitter.on(SourceEvent.Warning.class, onSourceWarningListener); + + eventEmitter.on(PlayerEvent.Muted.class, onMutedListener); + eventEmitter.on(PlayerEvent.Unmuted.class, onUnmutedListener); + + // Playback state events + eventEmitter.on(PlayerEvent.Play.class, onPlayListener); + eventEmitter.on(PlayerEvent.Playing.class, onPlayingListener); + eventEmitter.on(PlayerEvent.Paused.class, onPausedListener); + eventEmitter.on(PlayerEvent.StallEnded.class, onStallEndedListener); + eventEmitter.on(PlayerEvent.StallStarted.class, onStallStartedListener); + eventEmitter.on(PlayerEvent.PlaybackFinished.class, onPlaybackFinishedListener); + + // Seek events + eventEmitter.on(PlayerEvent.Seeked.class, onSeekedListener); + eventEmitter.on(PlayerEvent.Seek.class, onSeekListener); + + // Time shift events + eventEmitter.on(PlayerEvent.TimeShift.class, onTimeShiftListener); + eventEmitter.on(PlayerEvent.TimeShifted.class, onTimeShiftedListener); + + // Ad events + eventEmitter.on(PlayerEvent.AdBreakStarted.class, onAdBreakStarted); + eventEmitter.on(PlayerEvent.AdBreakFinished.class, onAdBreakFinished); + eventEmitter.on(PlayerEvent.AdStarted.class, onAdStartedListener); + eventEmitter.on(PlayerEvent.AdFinished.class, onAdFinishedListener); + eventEmitter.on(PlayerEvent.AdSkipped.class, onAdSkippedListener); + eventEmitter.on(PlayerEvent.AdError.class, onAdErrorListener); + eventEmitter.on(PlayerEvent.TimeChanged.class, onTimeChangedListener); + + eventEmitter.on(PlayerEvent.VideoPlaybackQualityChanged.class, onVideoPlaybackQualityChangedListener); + }); } private void detachBitmovinEventListeners() { - bitmovinPlayer.off(SourceEvent.Unloaded.class, onSourceUnloadedListener); - bitmovinPlayer.off(PlayerEvent.Error.class, onPlayerErrorListener); - bitmovinPlayer.off(SourceEvent.Error.class, onSourceErrorListener); - bitmovinPlayer.off(PlayerEvent.Warning.class, onPlayerWarningListener); - bitmovinPlayer.off(SourceEvent.Warning.class, onSourceWarningListener); - - bitmovinPlayer.off(PlayerEvent.Muted.class, onMutedListener); - bitmovinPlayer.off(PlayerEvent.Unmuted.class, onUnmutedListener); - - // Playback state events - bitmovinPlayer.off(PlayerEvent.Play.class, onPlayListener); - bitmovinPlayer.off(PlayerEvent.Playing.class, onPlayingListener); - bitmovinPlayer.off(PlayerEvent.Paused.class, onPausedListener); - bitmovinPlayer.off(PlayerEvent.StallEnded.class, onStallEndedListener); - bitmovinPlayer.off(PlayerEvent.StallStarted.class, onStallStartedListener); - bitmovinPlayer.off(PlayerEvent.PlaybackFinished.class, onPlaybackFinishedListener); - - // Seek events - bitmovinPlayer.off(PlayerEvent.Seeked.class, onSeekedListener); - bitmovinPlayer.off(PlayerEvent.Seek.class, onSeekListener); - - // Timeshift events - bitmovinPlayer.off(PlayerEvent.TimeShift.class, onTimeShiftListener); - bitmovinPlayer.off(PlayerEvent.TimeShifted.class, onTimeShiftedListener); - - // Ad events - bitmovinPlayer.off(PlayerEvent.AdBreakStarted.class, onAdBreakStarted); - bitmovinPlayer.off(PlayerEvent.AdBreakFinished.class, onAdBreakFinished); - bitmovinPlayer.off(PlayerEvent.AdStarted.class, onAdStartedListener); - bitmovinPlayer.off(PlayerEvent.AdFinished.class, onAdFinishedListener); - bitmovinPlayer.off(PlayerEvent.AdSkipped.class, onAdSkippedListener); - bitmovinPlayer.off(PlayerEvent.AdError.class, onAdErrorListener); - bitmovinPlayer.off(PlayerEvent.TimeChanged.class, onTimeChangedListener); - - bitmovinPlayer.off(PlayerEvent.VideoPlaybackQualityChanged.class, - onVideoPlaybackQualityChangedListener); + playerAdapter.withEventEmitter(bitmovinPlayer -> { + bitmovinPlayer.off(SourceEvent.Unloaded.class, onSourceUnloadedListener); + bitmovinPlayer.off(PlayerEvent.Error.class, onPlayerErrorListener); + bitmovinPlayer.off(SourceEvent.Error.class, onSourceErrorListener); + bitmovinPlayer.off(PlayerEvent.Warning.class, onPlayerWarningListener); + bitmovinPlayer.off(SourceEvent.Warning.class, onSourceWarningListener); + + bitmovinPlayer.off(PlayerEvent.Muted.class, onMutedListener); + bitmovinPlayer.off(PlayerEvent.Unmuted.class, onUnmutedListener); + + // Playback state events + bitmovinPlayer.off(PlayerEvent.Play.class, onPlayListener); + bitmovinPlayer.off(PlayerEvent.Playing.class, onPlayingListener); + bitmovinPlayer.off(PlayerEvent.Paused.class, onPausedListener); + bitmovinPlayer.off(PlayerEvent.StallEnded.class, onStallEndedListener); + bitmovinPlayer.off(PlayerEvent.StallStarted.class, onStallStartedListener); + bitmovinPlayer.off(PlayerEvent.PlaybackFinished.class, onPlaybackFinishedListener); + + // Seek events + bitmovinPlayer.off(PlayerEvent.Seeked.class, onSeekedListener); + bitmovinPlayer.off(PlayerEvent.Seek.class, onSeekListener); + + // Timeshift events + bitmovinPlayer.off(PlayerEvent.TimeShift.class, onTimeShiftListener); + bitmovinPlayer.off(PlayerEvent.TimeShifted.class, onTimeShiftedListener); + + // Ad events + bitmovinPlayer.off(PlayerEvent.AdBreakStarted.class, onAdBreakStarted); + bitmovinPlayer.off(PlayerEvent.AdBreakFinished.class, onAdBreakFinished); + bitmovinPlayer.off(PlayerEvent.AdStarted.class, onAdStartedListener); + bitmovinPlayer.off(PlayerEvent.AdFinished.class, onAdFinishedListener); + bitmovinPlayer.off(PlayerEvent.AdSkipped.class, onAdSkippedListener); + bitmovinPlayer.off(PlayerEvent.AdError.class, onAdErrorListener); + bitmovinPlayer.off(PlayerEvent.TimeChanged.class, onTimeChangedListener); + + bitmovinPlayer.off(PlayerEvent.VideoPlaybackQualityChanged.class, onVideoPlaybackQualityChangedListener); + }); } private synchronized void transitionState(ConvivaSdkConstants.PlayerState state) { @@ -605,7 +606,7 @@ public void onEvent(PlayerEvent.StallEnded stallEndedEvent) { new Handler().postDelayed(() -> { Log.d(TAG, "[Player Event] StallEnded"); ConvivaSdkConstants.PlayerState state = ConvivaSdkConstants.PlayerState.PLAYING; - if (bitmovinPlayer.isPaused()) { + if (playerAdapter.isPaused()) { state = ConvivaSdkConstants.PlayerState.PAUSED; } transitionState(state); @@ -651,7 +652,7 @@ public void setSeekEnd() { // Notify of seek buffering complete at this stage. Log.d(TAG, "[Player Event] Update state after buffering"); ConvivaSdkConstants.PlayerState state = ConvivaSdkConstants.PlayerState.PAUSED; - if (bitmovinPlayer.isPlaying()) { + if (playerAdapter.isPlaying()) { state = ConvivaSdkConstants.PlayerState.PLAYING; } transitionState(state); @@ -722,7 +723,7 @@ private Map adStartedToAdInfo(PlayerEvent.AdStarted adStartedEve adInfo.put(ConvivaSdkConstants.FRAMEWORK_VERSION, imaSdkVersion); } else { adInfo.put(ConvivaSdkConstants.FRAMEWORK_NAME, "Bitmovin"); - adInfo.put(ConvivaSdkConstants.FRAMEWORK_VERSION, playerHelper.getSdkVersionString()); + adInfo.put(ConvivaSdkConstants.FRAMEWORK_VERSION, Player.getSdkVersion()); } adInfo.put("c3.ad.position", getAdPosition(adStartedEvent.getTimeOffset())); adInfo.put(ConvivaSdkConstants.DURATION, adStartedEvent.getDuration()); @@ -775,7 +776,7 @@ private ConvivaSdkConstants.AdPosition getAdPosition(double timeOffset) { ConvivaSdkConstants.AdPosition adPosition = ConvivaSdkConstants.AdPosition.MIDROLL; if (timeOffset == 0.0) { adPosition = ConvivaSdkConstants.AdPosition.PREROLL; - } else if (timeOffset == bitmovinPlayer.getDuration()) { + } else if (timeOffset == playerAdapter.getDuration()) { adPosition = ConvivaSdkConstants.AdPosition.POSTROLL; } return adPosition; @@ -815,24 +816,10 @@ public void onEvent(PlayerEvent.AdError adError) { private final EventListener onTimeChangedListener = new EventListener() { @Override public void onEvent(PlayerEvent.TimeChanged timeChangedEvent) { - if (bitmovinPlayer.isLive()) { - double playerTimeshiftMax = bitmovinPlayer.getMaxTimeShift(); - double playerTimeshift = bitmovinPlayer.getTimeShift(); - long playerDurationMs = -(Math.round(playerTimeshiftMax * 1000)); - long playerPositionMs = playerDurationMs - -(Math.round(playerTimeshift * 1000)); - reportPlayHeadTime(playerPositionMs); - } else { - double currentTime = bitmovinPlayer.getCurrentTime(); - long playerDurationMs = (long) (currentTime * 1000); - reportPlayHeadTime(playerDurationMs); + if (isSessionActive) { + convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, playerAdapter.getPlayHeadTimeMillis()); } } }; - - private void reportPlayHeadTime(long playerDurationMs) { - if (isSessionActive) { - convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, playerDurationMs); - } - } // endregion } diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java new file mode 100644 index 0000000..0e01148 --- /dev/null +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java @@ -0,0 +1,109 @@ +package com.bitmovin.analytics.conviva; + +import com.bitmovin.analytics.conviva.helper.WithEventEmitter; +import com.bitmovin.player.api.Player; +import com.bitmovin.player.api.media.video.quality.VideoQuality; +import com.conviva.sdk.ConvivaSdkConstants; + +import java.util.HashMap; + +public class DefaultPlayerAdapter implements PlayerAdapter { + private final Player player; + + public DefaultPlayerAdapter(Player player) { + this.player = player; + } + + @Override + public ConvivaSdkConstants.PlayerState getPlayerState() { + ConvivaSdkConstants.PlayerState state; + if (player.isPaused()) { + state = ConvivaSdkConstants.PlayerState.PAUSED; + } else if (player.isStalled()) { + state = ConvivaSdkConstants.PlayerState.BUFFERING; + } else { + state = ConvivaSdkConstants.PlayerState.PLAYING; + } + return state; + } + + @Override + public HashMap getPlaybackVideoData() { + HashMap videoData = new HashMap<>(); + VideoQuality playbackVideoData = player.getPlaybackVideoData(); + if (playbackVideoData != null) { + videoData.put(ConvivaSdkConstants.PLAYBACK.RESOLUTION, new Object[]{playbackVideoData.getWidth(), playbackVideoData.getHeight()}); + videoData.put(ConvivaSdkConstants.PLAYBACK.BITRATE, new Object[]{playbackVideoData.getBitrate() / 1000}); + final int peakBitrate = playbackVideoData.getPeakBitrate(); + if (peakBitrate != VideoQuality.BITRATE_NO_VALUE) { + videoData.put(ConvivaSdkConstants.PLAYBACK.BITRATE, new Object[]{peakBitrate / 1000}); + } + final int averageBitrate = playbackVideoData.getAverageBitrate(); + if (averageBitrate != VideoQuality.BITRATE_NO_VALUE) { + videoData.put(ConvivaSdkConstants.PLAYBACK.AVG_BITRATE, new Object[]{averageBitrate / 1000}); + } + videoData.put(ConvivaSdkConstants.PLAYBACK.RENDERED_FRAMERATE, new Object[]{Math.round(playbackVideoData.getFrameRate())}); + } + return videoData; + } + + @Override + public String getStreamTitle() { + return player.getSource() == null ? null : player.getSource().getConfig().getTitle(); + } + + @Override + public String getStreamType() { + return player.getSource() == null ? null : player.getSource().getConfig().getType().name(); + } + + @Override + public String getStreamUrl() { + return player.getSource() == null ? null : player.getSource().getConfig().getUrl(); + } + + + @Override + public boolean isAd() { + return player.isAd(); + } + + @Override + public boolean isLive() { + return player.isLive(); + } + + @Override + public boolean isPaused() { + return player.isPaused(); + } + + @Override + public boolean isPlaying() { + return player.isPlaying(); + } + + @Override + public double getDuration() { + return player.getDuration(); + } + + @Override + public long getPlayHeadTimeMillis() { + if (player.isLive()) { + double playerTimeShiftMax = player.getMaxTimeShift(); + double playerTimeShift = player.getTimeShift(); + long playerDurationMs = -(Math.round(playerTimeShiftMax * 1000)); + return playerDurationMs - -(Math.round(playerTimeShift * 1000)); + + } else { + double currentTime = player.getCurrentTime(); + return (long) (currentTime * 1000); + } + } + + @Override + public void withEventEmitter(WithEventEmitter withEventEmitter) { + withEventEmitter.call(player); + } +} diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java new file mode 100644 index 0000000..e1225de --- /dev/null +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java @@ -0,0 +1,32 @@ +package com.bitmovin.analytics.conviva; + +import com.bitmovin.analytics.conviva.helper.WithEventEmitter; +import com.conviva.sdk.ConvivaSdkConstants; + +import java.util.HashMap; + +public interface PlayerAdapter { + ConvivaSdkConstants.PlayerState getPlayerState(); + + HashMap getPlaybackVideoData(); + + boolean isAd(); + + String getStreamTitle(); + + String getStreamType(); + + String getStreamUrl(); + + long getPlayHeadTimeMillis(); + + boolean isLive(); + + double getDuration(); + + void withEventEmitter(WithEventEmitter withEventEmitter); + + boolean isPaused(); + + boolean isPlaying(); +} diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java new file mode 100644 index 0000000..bc232b2 --- /dev/null +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java @@ -0,0 +1,8 @@ +package com.bitmovin.analytics.conviva.helper; + +import com.bitmovin.player.api.event.Event; +import com.bitmovin.player.api.event.JavaEventEmitter; + +public interface WithEventEmitter { + void call(JavaEventEmitter player); +} \ No newline at end of file diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultPlaybackInfoProvider.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultPlaybackInfoProvider.java deleted file mode 100644 index e8cab57..0000000 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultPlaybackInfoProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.bitmovin.analytics.conviva.ssai; - -import com.bitmovin.player.api.Player; -import com.bitmovin.player.api.media.video.quality.VideoQuality; -import com.conviva.sdk.ConvivaSdkConstants; - -import java.util.HashMap; - -public class DefaultPlaybackInfoProvider implements PlaybackInfoProvider { - private final Player player; - - public DefaultPlaybackInfoProvider(Player player) { - this.player = player; - } - - @Override - public ConvivaSdkConstants.PlayerState getPlayerState() { - ConvivaSdkConstants.PlayerState state; - if (player.isPaused()) { - state = ConvivaSdkConstants.PlayerState.PAUSED; - } else if (player.isStalled()) { - state = ConvivaSdkConstants.PlayerState.BUFFERING; - } else { - state = ConvivaSdkConstants.PlayerState.PLAYING; - } - return state; - } - - @Override - public HashMap getPlaybackVideoData() { - HashMap videoData = new HashMap<>(); - VideoQuality playbackVideoData = player.getPlaybackVideoData(); - if (playbackVideoData != null) { - videoData.put(ConvivaSdkConstants.PLAYBACK.RESOLUTION, new Object[]{playbackVideoData.getWidth(), playbackVideoData.getHeight()}); - final int peakBitrate = playbackVideoData.getPeakBitrate(); - if (peakBitrate != VideoQuality.BITRATE_NO_VALUE) { - videoData.put(ConvivaSdkConstants.PLAYBACK.BITRATE, new Object[]{peakBitrate / 1000}); - } - final int averageBitrate = playbackVideoData.getAverageBitrate(); - if (averageBitrate != VideoQuality.BITRATE_NO_VALUE) { - videoData.put(ConvivaSdkConstants.PLAYBACK.AVG_BITRATE, new Object[]{averageBitrate / 1000}); - } - videoData.put(ConvivaSdkConstants.PLAYBACK.RENDERED_FRAMERATE, new Object[]{Math.round(playbackVideoData.getFrameRate())}); - } - return videoData; - } -} diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java index b43b0bd..c015ac5 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java @@ -3,6 +3,7 @@ import android.util.Log; import com.bitmovin.analytics.conviva.ConvivaAnalyticsIntegration; +import com.bitmovin.analytics.conviva.PlayerAdapter; import com.conviva.sdk.ConvivaAdAnalytics; import com.conviva.sdk.ConvivaSdkConstants; import com.conviva.sdk.ConvivaVideoAnalytics; @@ -15,12 +16,12 @@ public class DefaultSsaiApi implements SsaiApi { private static final String TAG = "DefaultSsaiApi"; private final ConvivaVideoAnalytics convivaVideoAnalytics; private final ConvivaAdAnalytics convivaAdAnalytics; - private final PlaybackInfoProvider player; + private final PlayerAdapter playerAdapter; - public DefaultSsaiApi(ConvivaVideoAnalytics convivaVideoAnalytics, ConvivaAdAnalytics convivaAdAnalytics, PlaybackInfoProvider player) { + public DefaultSsaiApi(ConvivaVideoAnalytics convivaVideoAnalytics, ConvivaAdAnalytics convivaAdAnalytics, PlayerAdapter playerAdapter) { this.convivaVideoAnalytics = convivaVideoAnalytics; this.convivaAdAnalytics = convivaAdAnalytics; - this.player = player; + this.playerAdapter = playerAdapter; } private boolean isAdBreakActive = false; @@ -76,8 +77,8 @@ public void reportAdStarted(AdInfo adInfo) { } private void reportInitialAdMetrics() { - convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, player.getPlayerState()); - HashMap playbackVideoData = player.getPlaybackVideoData(); + convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, playerAdapter.getPlayerState()); + HashMap playbackVideoData = playerAdapter.getPlaybackVideoData(); for (Map.Entry entry : playbackVideoData.entrySet()) { convivaAdAnalytics.reportAdMetric(entry.getKey(), entry.getValue()); } diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/PlaybackInfoProvider.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/PlaybackInfoProvider.java deleted file mode 100644 index 43ddd39..0000000 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/PlaybackInfoProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.bitmovin.analytics.conviva.ssai; - -import com.conviva.sdk.ConvivaSdkConstants; - -import java.util.HashMap; - -public interface PlaybackInfoProvider { - ConvivaSdkConstants.PlayerState getPlayerState(); - - HashMap getPlaybackVideoData(); -} diff --git a/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt b/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt index f3c7049..6c3c45e 100644 --- a/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt +++ b/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt @@ -1,6 +1,7 @@ package com.bitmovin.analytics.conviva.ssai import android.util.Log +import com.bitmovin.analytics.conviva.PlayerAdapter import com.conviva.sdk.ConvivaAdAnalytics import com.conviva.sdk.ConvivaSdkConstants import com.conviva.sdk.ConvivaVideoAnalytics @@ -29,13 +30,13 @@ import strikt.assertions.isTrue class DefaultSsaiApiTest { private val videoAnalytics: ConvivaVideoAnalytics = mockk(relaxed = true) private val adAnalytics: ConvivaAdAnalytics = mockk() - private val playbackInfoProvider = mockk() + private val playerAdapter = mockk() private lateinit var ssaiApi: DefaultSsaiApi @Before fun beforeTest() { - every { playbackInfoProvider.playerState } returns ConvivaSdkConstants.PlayerState.PLAYING - every { playbackInfoProvider.playbackVideoData } returns hashMapOf>( + every { playerAdapter.playerState } returns ConvivaSdkConstants.PlayerState.PLAYING + every { playerAdapter.playbackVideoData } returns hashMapOf>( ConvivaSdkConstants.PLAYBACK.BITRATE to arrayOf(1), ConvivaSdkConstants.PLAYBACK.RESOLUTION to arrayOf(800, 1600), ConvivaSdkConstants.PLAYBACK.RENDERED_FRAMERATE to arrayOf(60), @@ -54,13 +55,13 @@ class DefaultSsaiApiTest { ssaiApi = DefaultSsaiApi( videoAnalytics, adAnalytics, - playbackInfoProvider, + playerAdapter, ) } @After fun afterTest() { - clearMocks(videoAnalytics, adAnalytics, playbackInfoProvider) + clearMocks(videoAnalytics, adAnalytics, playerAdapter) } @@ -131,7 +132,7 @@ class DefaultSsaiApiTest { @Test fun `reports ad playback state playing to conviva when ad starts while paused`() { - every { playbackInfoProvider.playerState } returns ConvivaSdkConstants.PlayerState.PAUSED + every { playerAdapter.playerState } returns ConvivaSdkConstants.PlayerState.PAUSED ssaiApi.reportAdBreakStarted() ssaiApi.reportAdStarted(SsaiApi.AdInfo()) @@ -146,7 +147,7 @@ class DefaultSsaiApiTest { @Test fun `reports ad playback state buffering to conviva when ad starts while stalling`() { - every { playbackInfoProvider.playerState } returns + every { playerAdapter.playerState } returns ConvivaSdkConstants.PlayerState.BUFFERING ssaiApi.reportAdBreakStarted() From 7df10b62856399bf89ab5346f415acd39250c8f4 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Sat, 24 Aug 2024 11:49:27 +0200 Subject: [PATCH 2/5] remove additional bitrate reporting * fixes failing unit test --- .../com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java index 0e01148..ee99ef7 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java @@ -33,7 +33,6 @@ public HashMap getPlaybackVideoData() { VideoQuality playbackVideoData = player.getPlaybackVideoData(); if (playbackVideoData != null) { videoData.put(ConvivaSdkConstants.PLAYBACK.RESOLUTION, new Object[]{playbackVideoData.getWidth(), playbackVideoData.getHeight()}); - videoData.put(ConvivaSdkConstants.PLAYBACK.BITRATE, new Object[]{playbackVideoData.getBitrate() / 1000}); final int peakBitrate = playbackVideoData.getPeakBitrate(); if (peakBitrate != VideoQuality.BITRATE_NO_VALUE) { videoData.put(ConvivaSdkConstants.PLAYBACK.BITRATE, new Object[]{peakBitrate / 1000}); From efc76ad2fa2f1feb44e0a1ca35a684b85e6514da Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Sat, 24 Aug 2024 11:56:28 +0200 Subject: [PATCH 3/5] fix some code style issues --- .../com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java | 1 - .../bitmovin/analytics/conviva/helper/WithEventEmitter.java | 2 +- .../com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java index ee99ef7..2452d62 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java @@ -94,7 +94,6 @@ public long getPlayHeadTimeMillis() { double playerTimeShift = player.getTimeShift(); long playerDurationMs = -(Math.round(playerTimeShiftMax * 1000)); return playerDurationMs - -(Math.round(playerTimeShift * 1000)); - } else { double currentTime = player.getCurrentTime(); return (long) (currentTime * 1000); diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java index bc232b2..6a342b3 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/helper/WithEventEmitter.java @@ -5,4 +5,4 @@ public interface WithEventEmitter { void call(JavaEventEmitter player); -} \ No newline at end of file +} diff --git a/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt b/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt index 6c3c45e..f4d817e 100644 --- a/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt +++ b/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt @@ -53,8 +53,8 @@ class DefaultSsaiApiTest { } ssaiApi = DefaultSsaiApi( - videoAnalytics, - adAnalytics, + videoAnalytics, + adAnalytics, playerAdapter, ) } From 8f5412437cda0b5f5d819ea8cc15b100ef901941 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 26 Aug 2024 13:58:56 +0200 Subject: [PATCH 4/5] rename PlayerAdapter to PlayerDecorator --- .../conviva/ConvivaAnalyticsIntegration.java | 40 +++++++++---------- ...apter.java => DefaultPlayerDecorator.java} | 4 +- ...layerAdapter.java => PlayerDecorator.java} | 2 +- .../conviva/ssai/DefaultSsaiApi.java | 12 +++--- .../conviva/ssai/DefaultSsaiApiTest.kt | 16 ++++---- 5 files changed, 36 insertions(+), 38 deletions(-) rename conviva/src/main/java/com/bitmovin/analytics/conviva/{DefaultPlayerAdapter.java => DefaultPlayerDecorator.java} (96%) rename conviva/src/main/java/com/bitmovin/analytics/conviva/{PlayerAdapter.java => PlayerDecorator.java} (94%) diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java index 4e35bd8..c34913b 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java @@ -18,8 +18,6 @@ import com.bitmovin.player.api.event.EventListener; import com.bitmovin.player.api.event.PlayerEvent; import com.bitmovin.player.api.event.SourceEvent; -import com.bitmovin.player.api.source.Source; -import com.bitmovin.player.api.source.SourceConfig; import com.conviva.sdk.ConvivaAdAnalytics; import com.conviva.sdk.ConvivaAnalytics; import com.conviva.sdk.ConvivaExperienceAnalytics; @@ -40,7 +38,7 @@ public class ConvivaAnalyticsIntegration { private final ConvivaVideoAnalytics convivaVideoAnalytics; private final ConvivaAdAnalytics convivaAdAnalytics; @NonNull - private final PlayerAdapter playerAdapter; + private final PlayerDecorator playerDecorator; private MetadataOverrides metadataOverrides; private final DefaultSsaiApi ssai; @@ -90,7 +88,7 @@ public ConvivaAnalyticsIntegration(Player player, ConvivaAdAnalytics adAnalytics, DefaultSsaiApi ssai ) { - playerAdapter = new DefaultPlayerAdapter(player); + playerDecorator = new DefaultPlayerDecorator(player); Map settings = new HashMap<>(); if (config.getGatewayUrl() != null || config.isDebugLoggingEnabled()) { if (config.getGatewayUrl() != null) { @@ -114,7 +112,7 @@ public ConvivaAnalyticsIntegration(Player player, } if (ssai == null) { - this.ssai = new DefaultSsaiApi(convivaVideoAnalytics, convivaAdAnalytics, playerAdapter); + this.ssai = new DefaultSsaiApi(convivaVideoAnalytics, convivaAdAnalytics, playerDecorator); } else { this.ssai = ssai; } @@ -128,7 +126,7 @@ private void setUpAdAnalyticsCallback() { @Override public void update() { if (isAdActive()) { - convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, ((long) (playerAdapter.getPlayHeadTimeMillis()))); + convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, ((long) (playerDecorator.getPlayHeadTimeMillis()))); } } @@ -139,7 +137,7 @@ public void update(String s) { } private boolean isAdActive() { - return playerAdapter.isAd() || ssai.isAdBreakActive(); + return playerDecorator.isAd() || ssai.isAdBreakActive(); } // region public methods @@ -176,7 +174,7 @@ public void sendCustomPlaybackEvent(String name, Map attributes) * If no source was loaded this method will throw an error. */ public void initializeSession() throws ConvivaAnalyticsException { - if ((playerAdapter.getStreamTitle() == null) + if ((playerDecorator.getStreamTitle() == null) && this.contentMetadataBuilder.getAssetName() == null) { throw new ConvivaAnalyticsException( "AssetName is missing. Load player source (with Title) first or set assetName via updateContentMetadata" @@ -350,7 +348,7 @@ private void updateSession() { } private void updatePlaybackVideoData() { - HashMap playbackVideoData = playerAdapter.getPlaybackVideoData(); + HashMap playbackVideoData = playerDecorator.getPlaybackVideoData(); for (Map.Entry entry : playbackVideoData.entrySet()) { convivaVideoAnalytics.reportPlaybackMetric(entry.getKey(), entry.getValue()); if (ssai.isAdBreakActive()) { @@ -364,8 +362,8 @@ private void createContentMetadata() { if (overriddenAssetName != null) { contentMetadataBuilder.setAssetName(overriddenAssetName); } else { - if (playerAdapter.getStreamTitle() != null) { - contentMetadataBuilder.setAssetName(playerAdapter.getStreamTitle()); + if (playerDecorator.getStreamTitle() != null) { + contentMetadataBuilder.setAssetName(playerDecorator.getStreamTitle()); } else { Log.w(TAG, "No asset name provided for content metadata."); } @@ -379,18 +377,18 @@ private void buildDynamicContentMetadata() { // streamType could be missing at time of session initialization // as source information could be unavailable at that time Map customInternTags = new HashMap<>(); - customInternTags.put(STREAM_TYPE, playerAdapter.getStreamType()); + customInternTags.put(STREAM_TYPE, playerDecorator.getStreamType()); customInternTags.put(INTEGRATION_VERSION, BuildConfig.VERSION_NAME); contentMetadataBuilder.setCustom(customInternTags); - if (playerAdapter.isLive()) { + if (playerDecorator.isLive()) { contentMetadataBuilder.setStreamType(ConvivaSdkConstants.StreamType.LIVE); } else { contentMetadataBuilder.setStreamType(ConvivaSdkConstants.StreamType.VOD); - contentMetadataBuilder.setDuration((int) playerAdapter.getDuration()); + contentMetadataBuilder.setDuration((int) playerDecorator.getDuration()); } - contentMetadataBuilder.setStreamUrl(playerAdapter.getStreamUrl()); + contentMetadataBuilder.setStreamUrl(playerDecorator.getStreamUrl()); } private void internalEndSession() { @@ -406,7 +404,7 @@ private void internalEndSession() { // endregion private void attachBitmovinEventListeners() { - playerAdapter.withEventEmitter(eventEmitter -> { + playerDecorator.withEventEmitter(eventEmitter -> { eventEmitter.on(SourceEvent.Unloaded.class, onSourceUnloadedListener); eventEmitter.on(PlayerEvent.Error.class, onPlayerErrorListener); eventEmitter.on(SourceEvent.Error.class, onSourceErrorListener); @@ -446,7 +444,7 @@ private void attachBitmovinEventListeners() { } private void detachBitmovinEventListeners() { - playerAdapter.withEventEmitter(bitmovinPlayer -> { + playerDecorator.withEventEmitter(bitmovinPlayer -> { bitmovinPlayer.off(SourceEvent.Unloaded.class, onSourceUnloadedListener); bitmovinPlayer.off(PlayerEvent.Error.class, onPlayerErrorListener); bitmovinPlayer.off(SourceEvent.Error.class, onSourceErrorListener); @@ -606,7 +604,7 @@ public void onEvent(PlayerEvent.StallEnded stallEndedEvent) { new Handler().postDelayed(() -> { Log.d(TAG, "[Player Event] StallEnded"); ConvivaSdkConstants.PlayerState state = ConvivaSdkConstants.PlayerState.PLAYING; - if (playerAdapter.isPaused()) { + if (playerDecorator.isPaused()) { state = ConvivaSdkConstants.PlayerState.PAUSED; } transitionState(state); @@ -652,7 +650,7 @@ public void setSeekEnd() { // Notify of seek buffering complete at this stage. Log.d(TAG, "[Player Event] Update state after buffering"); ConvivaSdkConstants.PlayerState state = ConvivaSdkConstants.PlayerState.PAUSED; - if (playerAdapter.isPlaying()) { + if (playerDecorator.isPlaying()) { state = ConvivaSdkConstants.PlayerState.PLAYING; } transitionState(state); @@ -776,7 +774,7 @@ private ConvivaSdkConstants.AdPosition getAdPosition(double timeOffset) { ConvivaSdkConstants.AdPosition adPosition = ConvivaSdkConstants.AdPosition.MIDROLL; if (timeOffset == 0.0) { adPosition = ConvivaSdkConstants.AdPosition.PREROLL; - } else if (timeOffset == playerAdapter.getDuration()) { + } else if (timeOffset == playerDecorator.getDuration()) { adPosition = ConvivaSdkConstants.AdPosition.POSTROLL; } return adPosition; @@ -817,7 +815,7 @@ public void onEvent(PlayerEvent.AdError adError) { @Override public void onEvent(PlayerEvent.TimeChanged timeChangedEvent) { if (isSessionActive) { - convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, playerAdapter.getPlayHeadTimeMillis()); + convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, playerDecorator.getPlayHeadTimeMillis()); } } }; diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerDecorator.java similarity index 96% rename from conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java rename to conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerDecorator.java index 2452d62..d809e38 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerAdapter.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/DefaultPlayerDecorator.java @@ -7,10 +7,10 @@ import java.util.HashMap; -public class DefaultPlayerAdapter implements PlayerAdapter { +public class DefaultPlayerDecorator implements PlayerDecorator { private final Player player; - public DefaultPlayerAdapter(Player player) { + public DefaultPlayerDecorator(Player player) { this.player = player; } diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerDecorator.java similarity index 94% rename from conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java rename to conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerDecorator.java index e1225de..629c8d5 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerAdapter.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/PlayerDecorator.java @@ -5,7 +5,7 @@ import java.util.HashMap; -public interface PlayerAdapter { +public interface PlayerDecorator { ConvivaSdkConstants.PlayerState getPlayerState(); HashMap getPlaybackVideoData(); diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java index c015ac5..4aaeb27 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java @@ -3,7 +3,7 @@ import android.util.Log; import com.bitmovin.analytics.conviva.ConvivaAnalyticsIntegration; -import com.bitmovin.analytics.conviva.PlayerAdapter; +import com.bitmovin.analytics.conviva.PlayerDecorator; import com.conviva.sdk.ConvivaAdAnalytics; import com.conviva.sdk.ConvivaSdkConstants; import com.conviva.sdk.ConvivaVideoAnalytics; @@ -16,12 +16,12 @@ public class DefaultSsaiApi implements SsaiApi { private static final String TAG = "DefaultSsaiApi"; private final ConvivaVideoAnalytics convivaVideoAnalytics; private final ConvivaAdAnalytics convivaAdAnalytics; - private final PlayerAdapter playerAdapter; + private final PlayerDecorator playerDecorator; - public DefaultSsaiApi(ConvivaVideoAnalytics convivaVideoAnalytics, ConvivaAdAnalytics convivaAdAnalytics, PlayerAdapter playerAdapter) { + public DefaultSsaiApi(ConvivaVideoAnalytics convivaVideoAnalytics, ConvivaAdAnalytics convivaAdAnalytics, PlayerDecorator playerDecorator) { this.convivaVideoAnalytics = convivaVideoAnalytics; this.convivaAdAnalytics = convivaAdAnalytics; - this.playerAdapter = playerAdapter; + this.playerDecorator = playerDecorator; } private boolean isAdBreakActive = false; @@ -77,8 +77,8 @@ public void reportAdStarted(AdInfo adInfo) { } private void reportInitialAdMetrics() { - convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, playerAdapter.getPlayerState()); - HashMap playbackVideoData = playerAdapter.getPlaybackVideoData(); + convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, playerDecorator.getPlayerState()); + HashMap playbackVideoData = playerDecorator.getPlaybackVideoData(); for (Map.Entry entry : playbackVideoData.entrySet()) { convivaAdAnalytics.reportAdMetric(entry.getKey(), entry.getValue()); } diff --git a/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt b/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt index f4d817e..4f9b319 100644 --- a/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt +++ b/conviva/src/test/kotlin/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApiTest.kt @@ -1,7 +1,7 @@ package com.bitmovin.analytics.conviva.ssai import android.util.Log -import com.bitmovin.analytics.conviva.PlayerAdapter +import com.bitmovin.analytics.conviva.PlayerDecorator import com.conviva.sdk.ConvivaAdAnalytics import com.conviva.sdk.ConvivaSdkConstants import com.conviva.sdk.ConvivaVideoAnalytics @@ -30,13 +30,13 @@ import strikt.assertions.isTrue class DefaultSsaiApiTest { private val videoAnalytics: ConvivaVideoAnalytics = mockk(relaxed = true) private val adAnalytics: ConvivaAdAnalytics = mockk() - private val playerAdapter = mockk() + private val playerDecorator = mockk() private lateinit var ssaiApi: DefaultSsaiApi @Before fun beforeTest() { - every { playerAdapter.playerState } returns ConvivaSdkConstants.PlayerState.PLAYING - every { playerAdapter.playbackVideoData } returns hashMapOf>( + every { playerDecorator.playerState } returns ConvivaSdkConstants.PlayerState.PLAYING + every { playerDecorator.playbackVideoData } returns hashMapOf>( ConvivaSdkConstants.PLAYBACK.BITRATE to arrayOf(1), ConvivaSdkConstants.PLAYBACK.RESOLUTION to arrayOf(800, 1600), ConvivaSdkConstants.PLAYBACK.RENDERED_FRAMERATE to arrayOf(60), @@ -55,13 +55,13 @@ class DefaultSsaiApiTest { ssaiApi = DefaultSsaiApi( videoAnalytics, adAnalytics, - playerAdapter, + playerDecorator, ) } @After fun afterTest() { - clearMocks(videoAnalytics, adAnalytics, playerAdapter) + clearMocks(videoAnalytics, adAnalytics, playerDecorator) } @@ -132,7 +132,7 @@ class DefaultSsaiApiTest { @Test fun `reports ad playback state playing to conviva when ad starts while paused`() { - every { playerAdapter.playerState } returns ConvivaSdkConstants.PlayerState.PAUSED + every { playerDecorator.playerState } returns ConvivaSdkConstants.PlayerState.PAUSED ssaiApi.reportAdBreakStarted() ssaiApi.reportAdStarted(SsaiApi.AdInfo()) @@ -147,7 +147,7 @@ class DefaultSsaiApiTest { @Test fun `reports ad playback state buffering to conviva when ad starts while stalling`() { - every { playerAdapter.playerState } returns + every { playerDecorator.playerState } returns ConvivaSdkConstants.PlayerState.BUFFERING ssaiApi.reportAdBreakStarted() From 1988b972175b375a2bea1932f754b5ef689e559b Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 26 Aug 2024 14:40:55 +0200 Subject: [PATCH 5/5] rename playerDecorator to player --- .../conviva/ConvivaAnalyticsIntegration.java | 38 +++++++++---------- .../conviva/ssai/DefaultSsaiApi.java | 14 ++++--- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java index c34913b..d486509 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/ConvivaAnalyticsIntegration.java @@ -38,7 +38,7 @@ public class ConvivaAnalyticsIntegration { private final ConvivaVideoAnalytics convivaVideoAnalytics; private final ConvivaAdAnalytics convivaAdAnalytics; @NonNull - private final PlayerDecorator playerDecorator; + private final PlayerDecorator player; private MetadataOverrides metadataOverrides; private final DefaultSsaiApi ssai; @@ -88,7 +88,7 @@ public ConvivaAnalyticsIntegration(Player player, ConvivaAdAnalytics adAnalytics, DefaultSsaiApi ssai ) { - playerDecorator = new DefaultPlayerDecorator(player); + this.player = new DefaultPlayerDecorator(player); Map settings = new HashMap<>(); if (config.getGatewayUrl() != null || config.isDebugLoggingEnabled()) { if (config.getGatewayUrl() != null) { @@ -112,7 +112,7 @@ public ConvivaAnalyticsIntegration(Player player, } if (ssai == null) { - this.ssai = new DefaultSsaiApi(convivaVideoAnalytics, convivaAdAnalytics, playerDecorator); + this.ssai = new DefaultSsaiApi(convivaVideoAnalytics, convivaAdAnalytics, this.player); } else { this.ssai = ssai; } @@ -126,7 +126,7 @@ private void setUpAdAnalyticsCallback() { @Override public void update() { if (isAdActive()) { - convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, ((long) (playerDecorator.getPlayHeadTimeMillis()))); + convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, ((long) (player.getPlayHeadTimeMillis()))); } } @@ -137,7 +137,7 @@ public void update(String s) { } private boolean isAdActive() { - return playerDecorator.isAd() || ssai.isAdBreakActive(); + return player.isAd() || ssai.isAdBreakActive(); } // region public methods @@ -174,7 +174,7 @@ public void sendCustomPlaybackEvent(String name, Map attributes) * If no source was loaded this method will throw an error. */ public void initializeSession() throws ConvivaAnalyticsException { - if ((playerDecorator.getStreamTitle() == null) + if ((player.getStreamTitle() == null) && this.contentMetadataBuilder.getAssetName() == null) { throw new ConvivaAnalyticsException( "AssetName is missing. Load player source (with Title) first or set assetName via updateContentMetadata" @@ -348,7 +348,7 @@ private void updateSession() { } private void updatePlaybackVideoData() { - HashMap playbackVideoData = playerDecorator.getPlaybackVideoData(); + HashMap playbackVideoData = player.getPlaybackVideoData(); for (Map.Entry entry : playbackVideoData.entrySet()) { convivaVideoAnalytics.reportPlaybackMetric(entry.getKey(), entry.getValue()); if (ssai.isAdBreakActive()) { @@ -362,8 +362,8 @@ private void createContentMetadata() { if (overriddenAssetName != null) { contentMetadataBuilder.setAssetName(overriddenAssetName); } else { - if (playerDecorator.getStreamTitle() != null) { - contentMetadataBuilder.setAssetName(playerDecorator.getStreamTitle()); + if (player.getStreamTitle() != null) { + contentMetadataBuilder.setAssetName(player.getStreamTitle()); } else { Log.w(TAG, "No asset name provided for content metadata."); } @@ -377,18 +377,18 @@ private void buildDynamicContentMetadata() { // streamType could be missing at time of session initialization // as source information could be unavailable at that time Map customInternTags = new HashMap<>(); - customInternTags.put(STREAM_TYPE, playerDecorator.getStreamType()); + customInternTags.put(STREAM_TYPE, player.getStreamType()); customInternTags.put(INTEGRATION_VERSION, BuildConfig.VERSION_NAME); contentMetadataBuilder.setCustom(customInternTags); - if (playerDecorator.isLive()) { + if (player.isLive()) { contentMetadataBuilder.setStreamType(ConvivaSdkConstants.StreamType.LIVE); } else { contentMetadataBuilder.setStreamType(ConvivaSdkConstants.StreamType.VOD); - contentMetadataBuilder.setDuration((int) playerDecorator.getDuration()); + contentMetadataBuilder.setDuration((int) player.getDuration()); } - contentMetadataBuilder.setStreamUrl(playerDecorator.getStreamUrl()); + contentMetadataBuilder.setStreamUrl(player.getStreamUrl()); } private void internalEndSession() { @@ -404,7 +404,7 @@ private void internalEndSession() { // endregion private void attachBitmovinEventListeners() { - playerDecorator.withEventEmitter(eventEmitter -> { + player.withEventEmitter(eventEmitter -> { eventEmitter.on(SourceEvent.Unloaded.class, onSourceUnloadedListener); eventEmitter.on(PlayerEvent.Error.class, onPlayerErrorListener); eventEmitter.on(SourceEvent.Error.class, onSourceErrorListener); @@ -444,7 +444,7 @@ private void attachBitmovinEventListeners() { } private void detachBitmovinEventListeners() { - playerDecorator.withEventEmitter(bitmovinPlayer -> { + player.withEventEmitter(bitmovinPlayer -> { bitmovinPlayer.off(SourceEvent.Unloaded.class, onSourceUnloadedListener); bitmovinPlayer.off(PlayerEvent.Error.class, onPlayerErrorListener); bitmovinPlayer.off(SourceEvent.Error.class, onSourceErrorListener); @@ -604,7 +604,7 @@ public void onEvent(PlayerEvent.StallEnded stallEndedEvent) { new Handler().postDelayed(() -> { Log.d(TAG, "[Player Event] StallEnded"); ConvivaSdkConstants.PlayerState state = ConvivaSdkConstants.PlayerState.PLAYING; - if (playerDecorator.isPaused()) { + if (player.isPaused()) { state = ConvivaSdkConstants.PlayerState.PAUSED; } transitionState(state); @@ -650,7 +650,7 @@ public void setSeekEnd() { // Notify of seek buffering complete at this stage. Log.d(TAG, "[Player Event] Update state after buffering"); ConvivaSdkConstants.PlayerState state = ConvivaSdkConstants.PlayerState.PAUSED; - if (playerDecorator.isPlaying()) { + if (player.isPlaying()) { state = ConvivaSdkConstants.PlayerState.PLAYING; } transitionState(state); @@ -774,7 +774,7 @@ private ConvivaSdkConstants.AdPosition getAdPosition(double timeOffset) { ConvivaSdkConstants.AdPosition adPosition = ConvivaSdkConstants.AdPosition.MIDROLL; if (timeOffset == 0.0) { adPosition = ConvivaSdkConstants.AdPosition.PREROLL; - } else if (timeOffset == playerDecorator.getDuration()) { + } else if (timeOffset == player.getDuration()) { adPosition = ConvivaSdkConstants.AdPosition.POSTROLL; } return adPosition; @@ -815,7 +815,7 @@ public void onEvent(PlayerEvent.AdError adError) { @Override public void onEvent(PlayerEvent.TimeChanged timeChangedEvent) { if (isSessionActive) { - convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, playerDecorator.getPlayHeadTimeMillis()); + convivaVideoAnalytics.reportPlaybackMetric(ConvivaSdkConstants.PLAYBACK.PLAY_HEAD_TIME, player.getPlayHeadTimeMillis()); } } }; diff --git a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java index 4aaeb27..4f93fcc 100644 --- a/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java +++ b/conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/DefaultSsaiApi.java @@ -16,12 +16,16 @@ public class DefaultSsaiApi implements SsaiApi { private static final String TAG = "DefaultSsaiApi"; private final ConvivaVideoAnalytics convivaVideoAnalytics; private final ConvivaAdAnalytics convivaAdAnalytics; - private final PlayerDecorator playerDecorator; + private final PlayerDecorator player; - public DefaultSsaiApi(ConvivaVideoAnalytics convivaVideoAnalytics, ConvivaAdAnalytics convivaAdAnalytics, PlayerDecorator playerDecorator) { + public DefaultSsaiApi( + ConvivaVideoAnalytics convivaVideoAnalytics, + ConvivaAdAnalytics convivaAdAnalytics, + PlayerDecorator player + ) { this.convivaVideoAnalytics = convivaVideoAnalytics; this.convivaAdAnalytics = convivaAdAnalytics; - this.playerDecorator = playerDecorator; + this.player = player; } private boolean isAdBreakActive = false; @@ -77,8 +81,8 @@ public void reportAdStarted(AdInfo adInfo) { } private void reportInitialAdMetrics() { - convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, playerDecorator.getPlayerState()); - HashMap playbackVideoData = playerDecorator.getPlaybackVideoData(); + convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, player.getPlayerState()); + HashMap playbackVideoData = player.getPlaybackVideoData(); for (Map.Entry entry : playbackVideoData.entrySet()) { convivaAdAnalytics.reportAdMetric(entry.getKey(), entry.getValue()); }