Skip to content

Commit

Permalink
Add support for changes from the SDK v9.1.0 and new Samples (#300)
Browse files Browse the repository at this point in the history
* PoC PAL SDK on SSAI

* Renaming to setNonce()

* Add PAL and Bumper Sample for KTS

* Adding Samples to the README file

* Fixing demo assets
  • Loading branch information
KEAMCRF authored Jul 23, 2024
1 parent 2e55e88 commit 6574642
Show file tree
Hide file tree
Showing 93 changed files with 1,149 additions and 7 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ The Issues tab is now closed. To report any problem or provide feedback, please

* [Basic Cast Sample App with Brightcove Cast Receiver](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/BasicCastBrightcoveReceiverSampleApp): This adds Google Chromecast support to the Brightcove Native Player SDK for Android, and demonstrates integration with the upated Brightcove Cast Receiver app v2.0. Please refer to the Release Notes in the v6.16.0 release of the Brightcove Native Player SDK for Android for more information.

* [Bumper Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/BumperSampleApp): This app shows how to setup the Brightcove ExoPlayer to play using a bumper video.

* [FreeWheel Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/FreeWheelSampleApp): This app shows how to use the Brightcove ExoPlayer with FreeWheel ads.

* [FreeWheel Widevine Modular Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/FreeWheelWidevineModularSampleApp): This app shows how to use the Brightcove ExoPlayer with FreeWheel ads and Widevine Modular content.
Expand All @@ -41,6 +43,8 @@ Note that in order to enable the FreeWheel sample apps, you must independently o

* [Basic SSAI Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/BasicSsaiSampleApp): This app shows how to configure an app to use the Brightcove Native Player for Android SSAI Plugin to play a video.

* [Basic SSAI PAL Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/BasicSSAIPALSampleApp): This app shows how to configure an app to use the Brightcove Native Player for Android SSAI Plugin to play a video and the PAL SDK from Google for Ad tracking.

* [ID3 Tags Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/ID3SampleApp): This app shows how to use the Brightcove ExoPlayer with ID3 tags.

* [HLS Live Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer/LiveSampleApp): This app shows how to use the Brightcove ExoPlayer with HLS Live and Live DVR content. Please note that a Live/DVR URL is not supplied with this sample app, and must be supplied by the developer.
Expand All @@ -57,6 +61,11 @@ Note that in order to enable the FreeWheel sample apps, you must independently o

* [Audio Only Sample App](https://github.com/KEAMCRF/android-player-samples/tree/AudioOnlySample/brightcove-exoplayer-kotlin/AudioOnlySampleApp): This app shows how to setup the Brightcove ExoPlayer with audio-only assets.

* [Basic SSAI PAL Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer-kotlin/BasicSSAIPALSampleApp): This app shows how to configure an app to use the Brightcove Native Player for Android SSAI Plugin to play a video and the PAL SDK from Google for Ad tracking.

* [Bumper Sample App](https://github.com/BrightcoveOS/android-player-samples/tree/master/brightcove-exoplayer-kotlin/BumperSampleApp): This app shows how to setup the Brightcove ExoPlayer to play using a bumper video.


## Installing the sample apps
Currently, all of the sample app projects must be installed together as a bundle. Individual sample app projects also have specific dependencies. For those specific dependencies, see the individual project descriptions above for details.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
44 changes: 44 additions & 0 deletions brightcove-exoplayer-kotlin/BasicSsaiPALSampleApp/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}

android {
namespace 'com.brightcove.ssai.pal.sample'
compileSdk ANDROID_COMPILE_SDK_VERSION

defaultConfig {
applicationId "com.brightcove.ssai.pal.sample"
minSdk ANDROID_MIN_SDK_VERSION
targetSdk ANDROID_TARGET_SDK_VERSION
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
buildFeatures {
viewBinding true
}
}

dependencies {
implementation "com.brightcove.player:android-appcompat-plugin:${anpVersion}"
implementation "androidx.constraintlayout:constraintlayout:${ANDROIDX_CONSTRAINT_LAYOUT}"
implementation "androidx.appcompat:appcompat:${ANDROIDX_APPCOMPAT}"
implementation "com.google.android.material:material:${ANDROID_MATERIAL}"
implementation "com.google.android.gms:play-services-pal:${GOOGLE_IMA_PAL_VERSION}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Base.Theme.BasicSsaiSample">
<activity
android:name=".BasicSsaiPALSampleAppActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package com.brightcove.ssai.pal.sample

import android.os.Bundle
import android.util.Log
import com.brightcove.player.Sdk
import com.brightcove.player.appcompat.BrightcovePlayerActivity
import com.brightcove.player.edge.Catalog
import com.brightcove.player.edge.VideoListener
import com.brightcove.player.event.Event
import com.brightcove.player.event.EventType
import com.brightcove.player.model.Video
import com.brightcove.player.network.HttpRequestConfig
import com.brightcove.ssai.SSAIComponent
import com.brightcove.ssai.event.SSAIEventType
import com.brightcove.ssai.omid.AdEventType
import com.brightcove.ssai.omid.OpenMeasurementTracker
import com.brightcove.ssai.pal.sample.databinding.ActivityBasicSsaiPalSampleBinding
import com.google.ads.interactivemedia.pal.ConsentSettings
import com.google.ads.interactivemedia.pal.NonceLoader
import com.google.ads.interactivemedia.pal.NonceManager
import com.google.ads.interactivemedia.pal.NonceRequest
import com.iab.omid.library.brightcove.adsession.FriendlyObstructionPurpose


class BasicSsaiPALSampleAppActivity : BrightcovePlayerActivity() {

private var plugin: SSAIComponent? = null
private var tracker: OpenMeasurementTracker? = null

private var nonceLoader: NonceLoader? = null
private var nonceManager: NonceManager? = null
private var consentSettings: ConsentSettings? = null
private var catalog: Catalog? = null

private lateinit var binding: ActivityBasicSsaiPalSampleBinding

override fun onCreate(savedInstanceState: Bundle?) {
// When extending the BrightcovePlayer, we must assign brightcoveVideoView before
// entering the superclass. This allows for some stock video player lifecycle
// management.
binding = ActivityBasicSsaiPalSampleBinding.inflate(layoutInflater)
setContentView(binding.root)
baseVideoView = binding.brightcoveVideoView
super.onCreate(savedInstanceState)

val eventEmitter = baseVideoView.eventEmitter

//PAL
// The default value for allowStorage() is false, but can be
// changed once the appropriate consent has been gathered. The
// getConsentToStorage() method is a placeholder for the publisher's own
// method of obtaining user consent, either by integrating with a CMP or
// based on other methods the publisher chooses to handle storage consent.
//boolean isConsentToStorage = getConsentToStorage();
consentSettings = ConsentSettings.builder().allowStorage(false).build()

// It is important to instantiate the NonceLoader as early as possible to
// allow it to initialize and preload data for a faster experience when
// loading the NonceManager. A new NonceLoader will need to be instantiated
//if the ConsentSettings change for the user.

nonceLoader = NonceLoader( this, consentSettings!!)

generateNonceForAdRequest()

eventEmitter.on(EventType.PLAY) { sendPlaybackStart() }

eventEmitter.on(EventType.COMPLETED) { sendPlaybackEnd() }

eventEmitter.on(SSAIEventType.AD_CLICKED) { sendAdClick() }

catalog = Catalog.Builder(eventEmitter, getString(R.string.sdk_demo_account))
.setBaseURL(Catalog.DEFAULT_EDGE_BASE_URL)
.setPolicy(getString(R.string.sdk_demo_policy_key))
.build()

// Setup the error event handler for the SSAI plugin.
registerErrorEventHandler()
setupOpenMeasurement()
plugin = SSAIComponent(this, baseVideoView)

// Set the companion ad container.
plugin?.addCompanionContainer(binding.adFrame)
}

private fun generateNonceForAdRequest() {
val supportedApiFrameWorksSet: MutableSet<Int> = HashSet()
// The values 2, 7, and 9 correspond to player support for
// VPAID 2.0, OMID 1.0, and SIMID 1.1.
supportedApiFrameWorksSet.add(2)
supportedApiFrameWorksSet.add(7)
supportedApiFrameWorksSet.add(9)

val nonceRequest = NonceRequest.builder()
.descriptionURL("https://example.com/content1")
.iconsSupported(true)
.omidPartnerVersion("6.2.1")
.omidPartnerName("Example Publisher")
.playerType("ExamplePlayerType")
.playerVersion("1.0.0")
.ppid("testPpid")
.sessionId("Sample SID")
.supportedApiFrameworks(supportedApiFrameWorksSet)
.videoPlayerHeight(480)
.videoPlayerWidth(640)
.willAdAutoPlay(true)
.willAdPlayMuted(true)
.build()

nonceLoader?.loadNonceManager(nonceRequest)?.addOnSuccessListener { manager ->
nonceManager = manager
val nonceString = manager?.nonce
plugin?.setNonce(nonceString)
Log.d("PALSample", "Generated nonce: $nonceString")
// Set the HttpRequestConfig with the Ad Config Id configured in
// your https://studio.brightcove.com account.
val httpRequestConfig = HttpRequestConfig.Builder()
.addQueryParameter(
HttpRequestConfig.KEY_AD_CONFIG_ID,
AD_CONFIG_ID_QUERY_PARAM_VALUE
)
.build()

catalog?.findVideoByID(
getString(R.string.sdk_demo_video_id),
httpRequestConfig,
object : VideoListener() {
override fun onVideo(video: Video) {
// The Video Sources will have a VMAP url which will be processed by the SSAI plugin,
// If there is not a VMAP url, or if there are any requesting or parsing error,
// an EventType.ERROR event will be emitted.
plugin?.processVideo(video)
}
})
}?.addOnFailureListener { error ->
Log.e("PALSample", "Nonce generation failed: " + error.message)
}
}

private fun sendAdClick() {
if (nonceManager != null) {
nonceManager?.sendAdClick()
Log.d(TAG,"PAL sendAdClick() called"
)
}
}

private fun sendPlaybackStart() {
if (nonceManager != null) {
nonceManager?.sendPlaybackStart()
Log.d(TAG,"PAL sendPlaybackStart() called"
)
}
}

private fun sendPlaybackEnd() {
if (nonceManager != null) {
nonceManager?.sendPlaybackEnd()
Log.d(TAG,"PAL sendPlaybackEnd() called"
)
}
}

override fun onDestroy() {
super.onDestroy()
if (tracker != null && isFinishing) {
tracker?.stop()
}
if (nonceLoader != null) {
nonceLoader!!.release()
}
}

private fun setupOpenMeasurement() {
binding.omToggle.setOnCheckedChangeListener { _, isChecked: Boolean ->
if (isChecked) {
tracker?.start()
} else {
tracker?.stop()
}
}

// Initialize the OpenMeasurementTracker
tracker = OpenMeasurementTracker.Factory(PARTNER_NAME, PARTNER_VERSION, baseVideoView).create()

// NOTE: The ad used in the sample does not have an `AdVerification` element and will not
// send tracking events. You may verify OpenMeasurement via the following listener:
tracker?.addListener(object : OpenMeasurementTracker.Listener {
override fun onEvent(adEventType: AdEventType) {
Log.d(TAG, "onEvent() called with: adEventType = [$adEventType]")
}

override fun onStartTracking() {
Log.d(TAG, "onStartTracking() called")
}

override fun onStoppedTracking() {
Log.d(TAG, "onStoppedTracking() called")
}
})

// Example to register a view that should be considered as a friendly obstruction
tracker?.addFriendlyObstruction(binding.adFrame, FriendlyObstructionPurpose.OTHER, "Ad frame")

// Start the tracker, if enabled.
if (binding.omToggle.isChecked) {
tracker?.start()
}
}

private fun registerErrorEventHandler() {
// Handle the case where the ad data URL has not been supplied to the plugin.
val eventEmitter = baseVideoView.eventEmitter
eventEmitter.on(EventType.ERROR) { event: Event ->
Log.e(TAG, event.type)
}
}

companion object {
private const val TAG = "MainActivity"
private const val AD_CONFIG_ID_QUERY_PARAM_VALUE = "ba5e4879-77f0-424b-8c98-706ae5ad7eec"
private const val PARTNER_NAME = "dummyVendor"
private val PARTNER_VERSION = Sdk.getVersionName()
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6574642

Please sign in to comment.