Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce SSAI API #72

Merged
merged 5 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.bitmovin.analytics.conviva.ssai;

public enum AdPosition {
PREROLL,
MIDROLL,
POSTROLL;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.bitmovin.analytics.conviva.ssai;

import com.bitmovin.player.api.Player;
import com.conviva.sdk.ConvivaSdkConstants;

public class DefaultPlaybackStateProvider implements PlaybackStateProvider {
private final Player player;

public DefaultPlaybackStateProvider(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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package com.bitmovin.analytics.conviva.ssai;

import android.util.Log;

import com.conviva.sdk.ConvivaAdAnalytics;
import com.conviva.sdk.ConvivaSdkConstants;
import com.conviva.sdk.ConvivaVideoAnalytics;

import java.util.HashMap;
import java.util.Map;


public class DefaultSsaiApi implements SsaiApi {
private static final String TAG = "DefaultSsaiApi";
private final ConvivaVideoAnalytics convivaVideoAnalytics;
private final ConvivaAdAnalytics convivaAdAnalytics;
private final PlaybackStateProvider player;

public DefaultSsaiApi(ConvivaVideoAnalytics convivaVideoAnalytics, ConvivaAdAnalytics convivaAdAnalytics, PlaybackStateProvider player) {
this.convivaVideoAnalytics = convivaVideoAnalytics;
this.convivaAdAnalytics = convivaAdAnalytics;
this.player = player;
}

private boolean isAdBreakActive = false;

@Override
public boolean isAdBreakActive() {
return isAdBreakActive;
}

@Override
public void reportAdBreakStarted() {
reportAdBreakStarted(null);
}

public void reset() {
isAdBreakActive = false;
}
matamegger marked this conversation as resolved.
Show resolved Hide resolved

@Override
public void reportAdBreakStarted(Map<String, Object> adBreakInfo) {
if (isAdBreakActive) {
Log.d(TAG, "Server side ad break already active");
return;
}
isAdBreakActive = true;
Log.d(TAG, "Server side ad break started");
convivaVideoAnalytics.reportAdBreakStarted(ConvivaSdkConstants.AdPlayer.CONTENT, ConvivaSdkConstants.AdType.SERVER_SIDE, adBreakInfo);
}


@Override
public void reportAdBreakFinished() {
if (!isAdBreakActive) {
Log.d(TAG, "No server side ad break active");
return;
}
isAdBreakActive = false;
Log.d(TAG, "Server side ad break finished");
convivaVideoAnalytics.reportAdBreakEnded();
}


@Override
public void reportAdStarted(AdInfo adInfo) {
if (!isAdBreakActive) {
Log.d(TAG, "No server side ad break active");
return;
}
Log.d(TAG, "Server side ad started");
convivaAdAnalytics.reportAdStarted(convertToConvivaAdInfo(adInfo));
convivaAdAnalytics.reportAdMetric(ConvivaSdkConstants.PLAYBACK.PLAYER_STATE, player.getPlayerState());
}

@Override
public void reportAdFinished() {
if (!isAdBreakActive) {
Log.d(TAG, "No ad break active");
return;
}
Log.d(TAG, "Server side ad finished");
convivaAdAnalytics.reportAdEnded();
}

@Override
public void reportAdSkipped() {
if (!isAdBreakActive) {
Log.d(TAG, "No ad break active");
return;
}
isAdBreakActive = false;
Log.d(TAG, "Server side ad skipped");
convivaAdAnalytics.reportAdSkipped();
}

@Override
public void updateAdInfo(AdInfo adInfo) {
if (!isAdBreakActive) {
Log.d(TAG, "No ad break active");
return;
}
Log.d(TAG, "Setting ad info");

convivaAdAnalytics.setAdInfo(convertToConvivaAdInfo(adInfo));
}

private static Map<String, Object> convertToConvivaAdInfo(AdInfo adInfo) {
HashMap<String, Object> convivaAdInfo = new HashMap<>();
convivaAdInfo.put("c3.ad.id", "NA");
convivaAdInfo.put("c3.ad.system", "NA");
convivaAdInfo.put("c3.ad.mediaFileApiFramework", "NA");
convivaAdInfo.put("c3.ad.firstAdSystem", "NA");
convivaAdInfo.put("c3.ad.firstAdId", "NA");
convivaAdInfo.put("c3.ad.firstCreativeId", "NA");
convivaAdInfo.put("c3.ad.technology", "Server Side");

convivaAdInfo.put("c3.ad.isSlate", adInfo.isSlate());

if (adInfo.getTitle() != null) {
convivaAdInfo.put(ConvivaSdkConstants.ASSET_NAME, adInfo.getTitle());
}
if (adInfo.getDuration() != 0) {
convivaAdInfo.put(ConvivaSdkConstants.DURATION, adInfo.getDuration());
}
if (adInfo.getId() != null) {
convivaAdInfo.put("c3.ad.id", adInfo.getId());
}
if (adInfo.getAdSystem() != null) {
convivaAdInfo.put("c3.ad.system", adInfo.getAdSystem());
}
if (adInfo.getPosition() != null) {
convivaAdInfo.put("c3.ad.position", toConvivaAdPosition(adInfo.getPosition()));
}
if (adInfo.getAdStitcher() != null) {
convivaAdInfo.put("c3.ad.stitcher", adInfo.getAdStitcher());
}
if (adInfo.getAdditionalMetadata() != null) {
convivaAdInfo.putAll(adInfo.getAdditionalMetadata());
}

return convivaAdInfo;
}

private static ConvivaSdkConstants.AdPosition toConvivaAdPosition(AdPosition position) {
switch (position) {
case PREROLL:
return ConvivaSdkConstants.AdPosition.PREROLL;
case POSTROLL:
return ConvivaSdkConstants.AdPosition.POSTROLL;
default:
return ConvivaSdkConstants.AdPosition.MIDROLL;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.bitmovin.analytics.conviva.ssai;

import com.conviva.sdk.ConvivaSdkConstants;

public interface PlaybackStateProvider {
ConvivaSdkConstants.PlayerState getPlayerState();
}
168 changes: 168 additions & 0 deletions conviva/src/main/java/com/bitmovin/analytics/conviva/ssai/SsaiApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package com.bitmovin.analytics.conviva.ssai;

import java.util.Map;

/**
* Enables reporting of server-side ad breaks and ads.
*/
public interface SsaiApi {
/**
* Checks if a server-side ad break is currently active.
strangesource marked this conversation as resolved.
Show resolved Hide resolved
*
* @return <code>true</code> if a server-side ad break is active, <code>false</code> otherwise.
*/
boolean isAdBreakActive();

/**
* Reports the start of a server-side ad break. Must be called before the first ad starts.
* Has no effect if a server-side ad break is already playing.
*/
void reportAdBreakStarted();

/**
* Reports the start of a server-side ad break. Must be called before the first ad starts.
* Has no effect if a server-side ad break is already playing.
*
* @param adBreakInfo Map containing metadata about the server-side ad break. Can be <code>null</code>.
*/
void reportAdBreakStarted(Map<String, Object> adBreakInfo);

/**
* Reports the end of a server-side ad break. Must be called after the last ad has finished.
* Has no effect if no server-side ad break is currently active.
*/
void reportAdBreakFinished();

/**
* Reports the start of a server-side ad.
*
* @param adInfo Object containing metadata about the server-side ad.
*/
matamegger marked this conversation as resolved.
Show resolved Hide resolved
void reportAdStarted(AdInfo adInfo);

/**
* Reports the end of a server-side ad.
* Has no effect if no server-side ad is currently playing.
*/
void reportAdFinished();

/**
* Reports that the current ad was skipped.
* Has no effect if no server-side ad is playing.
*/
void reportAdSkipped();

/**
* Updates the ad metadata during an active client-side or server-side ad.
* Has no effect if no server-side ad is playing.
*
* @param adInfo Object containing metadata about the ad.
*/
void updateAdInfo(AdInfo adInfo);

/**
* Represents metadata for an ad.
*/
class AdInfo {
private String title;
private double duration;
private String id;
private String adSystem;
private AdPosition position;
private boolean isSlate = false;
private String adStitcher;
private Map<String, Object> additionalMetadata;

public double getDuration() {
return duration;
}

/**
* Duration of the ad, in seconds.
*/
public void setDuration(double duration) {
this.duration = duration;
}

public String getId() {
return id;
}

/**
* The ad ID extracted from the ad server that contains the ad creative.
*/
public void setId(String id) {
this.id = id;
}

public String getAdSystem() {
return adSystem;
}

/**
* The name of the ad system (i.e., the ad server).
*/
public void setAdSystem(String adSystem) {
this.adSystem = adSystem;
}

public AdPosition getPosition() {
return position;
}

/**
* The position of the ad.
*/
public void setPosition(AdPosition position) {
this.position = position;
}

public boolean isSlate() {
return isSlate;
}

/**
* Indicates whether this ad is a slate or not. Set to <code>true</code> for slate and <code>false</code> for a regular ad.
* Default is <code>false</code>.
*/
public void setSlate(boolean slate) {
isSlate = slate;
}

public String getAdStitcher() {
return adStitcher;
}

/**
* The name of the ad stitcher.
*/
public void setAdStitcher(String adStitcher) {
this.adStitcher = adStitcher;
}

public Map<String, Object> getAdditionalMetadata() {
return additionalMetadata;
}

/**
* Additional ad metadata. This is a map of key-value pairs that can be used to pass additional metadata about the ad.
* A list of ad metadata can be found here: <a href="https://pulse.conviva.com/learning-center/content/sensor_developer_center/sensor_integration/android/android_stream_sensor.htm#IntegrateAdManagers">Conviva documentation</a>
* <p>
* Metadata provided here will supersede any data provided in the ad break info.
*/
public void setAdditionalMetadata(Map<String, Object> additionalMetadata) {
this.additionalMetadata = additionalMetadata;
}

public String getTitle() {
return title;
}

/**
* The title of the ad.
*/
public void setTitle(String title) {
this.title = title;
}
}
}
Loading