Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:bitmovin-engineering/bitmovin-an…
Browse files Browse the repository at this point in the history
…alytics-collector-roku-internal into develop
  • Loading branch information
Andr3wid committed Sep 2, 2024
2 parents ed1dd28 + 4c243c5 commit 7aa34fc
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 12 deletions.
11 changes: 10 additions & 1 deletion bitmovinPlayerCollector/bitmovinPlayerCollector.brs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ sub onError()

' Stop collecting data
unobserveFields()

m.collectorCore.callFunc("onError", m.player.error.code, m.player.error.message)
end sub

' Handler for player's onDestroy callback.
Expand Down Expand Up @@ -361,7 +363,7 @@ sub setAnalyticsConfig(config)
end sub

function getImpressionIdForSample()
return m.collectorCore.callFunc("createImpressionId")
return m.collectorCore.callFunc("getRandomImpressionId")
end function

function getPlayerKeyFromManifest(appInfo)
Expand Down Expand Up @@ -524,3 +526,10 @@ end function
function adBreakEnd()
m.collectorCore.callFunc("adBreakEnd")
end function

'Function to report that an `adQuartile` has been reached during an SSAI-based ad.
'@param {String} adQuartile - The adQuartile to be reported. Values can either be `"first'`, `"midpoint"`, `"third"` or `"completed"`.
'@param {Object} adQuartileMetadata - Metadata to be reported with the `adQuartile`. Can currently only contain a `failedBeaconUrl` to indicate that pinging a related beacon was not successful.
function adQuartileFinished(adQuartile, adQuartileMetadata = invalid)
m.collectorCore.callFunc("adQuartileFinished", adQuartile, adQuartileMetadata)
end function
47 changes: 44 additions & 3 deletions collectorCore/analyticsDataTask.brs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ sub init()
m.heartbeatTimer = CreateObject("roTimespan")
m.appInfo = CreateObject("roAppInfo")
m.licensingUrl = m.config.serviceEndpoints.analyticsLicense
m.dataUrl = m.config.serviceEndpoints.analyticsData
m.licensingResponse = {}
m.AnalyticsRequestTypes = getAnalyticsRequestTypes()

m.AnalyticsDataTaskControlValues = getAnalyticsDataTaskControlValues()
m.AnalyticsDataTaskFieldNames = getAnlyticsDataTaskFieldNames()
end sub

function getDataUrl(analyticsRequestType)
if analyticsRequestType = m.AnalyticsRequestTypes.REGULAR then
return m.config.serviceEndpoints.analyticsData
else if analyticsRequestType = m.AnalyticsRequestTypes.AD_ENGAGEMENT then
return m.config.serviceEndpoints.analyticsAdData
else
' Unknown request type - assume REGULAR request
return m.config.serviceEndpoints.analyticsData
end if
end function

sub runTask(param = invalid)
if isTaskRunning() then return

Expand Down Expand Up @@ -127,14 +138,21 @@ sub sendAnalyticsLicensingRequest(licensingData)
end sub

sub sendAnalyticsData(eventData)
analyticsEndpointUrl = getDataUrl(eventData.requestType)
payload = eventData.requestData
isSsaiRelated = eventData.isSsaiRelated

if isSsaiRelated <> invalid and isSsaiRelated then analyticsEndpointUrl = addQueryParamToUrl(analyticsEndpointUrl, "routingParam", "ssai")

http = CreateObject("roUrlTransfer")
http.SetCertificatesFile("common:/certs/ca-bundle.crt")
port = CreateObject("roMessagePort")
http.setPort(port)
http.setUrl(m.dataUrl)
http.setUrl(analyticsEndpointUrl)
http.AddHeader("Origin", m.top.licensingData.domain)

data = FormatJson(eventData)

data = FormatJson(payload)

if http.asyncPostFromString(data)
msg = wait(0, port)
Expand All @@ -152,6 +170,29 @@ sub sendAnalyticsData(eventData)
end if
end sub

function addQueryParamToUrl(url, queryParamName, queryParamValue)
queryParamKeyValuePair = queryParamName + "=" + queryParamValue
appendableQueryParam = ""

splitUrl = url.split("?")
hasUrlQueryParamPart = splitUrl.Count() > 1

if hasUrlQueryParamPart
domainPart = splitUrl[0]
queryParamPart = splitUrl[1]

isQueryParamPartEmpty = len(queryParamPart) = 0

if not isQueryParamPartEmpty then appendableQueryParam += "&"
else
appendableQueryParam += "?"
end if

appendableQueryParam += queryParamKeyValuePair

return url + appendableQueryParam
end function

sub sendAnalyticsEventsFromQueue()
if m.analyticsEventsQueue.Count() = 0 then return

Expand Down
1 change: 1 addition & 0 deletions collectorCore/baseCollector.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
<function name="adBreakStart"/>
<function name="adStart"/>
<function name="adBreakEnd"/>
<function name="adQuartileFinished"/>
</interface>
</component>
93 changes: 86 additions & 7 deletions collectorCore/collectorCore.brs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ sub init()
m.deviceInfo = CreateObject("roDeviceInfo")
m.sectionRegistryName = "BitmovinAnalytics"
m.AnalyticsDataTask = m.top.findNode("analyticsDataTask")
m.AnalyticsRequestTypes = getAnalyticsRequestTypes()
m.analyticsConfig = CreateObject("roAssociativeArray")
m.sample = invalid
end sub
Expand Down Expand Up @@ -87,10 +88,70 @@ sub setupSample()
m.sample.language = m.deviceInfo.GetCurrentLocale()

m.sample.sequenceNumber = 0
m.sample.impressionId = createImpressionId()
m.sample.impressionId = getRandomImpressionId()
m.sample.deviceInformation = getDeviceInformation()
end sub

function getBaseAdSample()
if m.sample = invalid then setupSample()

baseAdSample = {
platform: m.sample.platform,
screenHeight: m.sample.screenHeight,
screenWidth: m.sample.screenWidth,
adPlaybackHeight: m.sample.screenHeight,
adPlaybackWidth: m.sample.screenWidth,
streamFormat: m.sample.streamFormat,
videoImpressionId: m.sample.impressionId,
userAgent: m.sample.userAgent,
language: m.sample.language,
domain: m.sample.domain,
player: m.sample.player,
playerKey: m.sample.playerKey,
key: m.sample.key,
userId: m.sample.userId,
version: m.sample.version,
playerTech: m.sample.playerTech,
path: m.sample.path,
analyticsVersion: getVersion(),
adImpressionId: m.sample.adImpressionId,
adIndex: m.adIndex,
videoId: m.sample.videoId,
videoTitle: m.sample.videoTitle,
userId: m.sample.userId,
size: m.sample.size,
time: m.sample.time,
videoWindowHeight: m.sample.videoWindowHeight,
videoWindowWidth: m.sample.videoWindowWidth,
}

if m.currentAdMetadata <> invalid
baseAdSample.append({
adPosition: m.currentAdMetadata.adPosition,
adId: m.currentAdMetadata.adId,
adSystem: m.currentAdMetadata.adSystem
})
end if

baseAdSample.append(m.analyticsConfig)
adMetadataCustomDataFields = getCurrentAdMetadataCustomDataFields()
baseAdSample.append(adMetadataCustomDataFields)

return baseAdSample
end function

function getCurrentAdMetadataCustomDataFields()
if m.adCustomData = invalid return {}

populatedCustomDataFields = {}

for each key in m.adCustomData.keys()
if m.adCustomData[key] <> invalid then populatedCustomDataFields[key] = m.adCustomData[key]
end for

return populatedCustomDataFields
end function

sub clearSampleValues()
m.sample.ad = 0
m.sample.paused = 0
Expand Down Expand Up @@ -130,8 +191,8 @@ function getDeviceInformation()
}
end function

' Create a new unique impression ID.
function createImpressionId()
' Generates a random UUID that can be used as an (ad-)impression id.
function getRandomImpressionId()
return lcase(m.deviceInfo.GetRandomUUID())
end function

Expand All @@ -157,20 +218,38 @@ function getPersistedUserId(sectionRegistryName)
end function

' TODO: Error handling if the keys are invalid
sub sendAnalyticsRequestAndClearValues()
sub sendAnalyticsRequestAndClearValues(analyticsRequestType = m.AnalyticsRequestTypes.REGULAR)
manipulateSampleForSsai()
m.AnalyticsDataTask.eventData = m.sample
m.AnalyticsDataTask.eventData = {
requestType: analyticsRequestType
requestData: m.sample
isSsaiRelated: isCurrentSampleSsaiRelated()
}
m.sample.sequenceNumber++

sendAnalyticsRequest()
clearSampleValues()
end sub

sub createTempMetadataSampleAndSendAnalyticsRequest(updatedSampleData)
sub createTempMetadataSampleAndSendAnalyticsRequest(updatedSampleData, analyticsRequestType = m.AnalyticsRequestTypes.REGULAR)
if updatedSampleData = invalid return

sendOnceSample = createSendOnceSample(updatedSampleData)
m.AnalyticsDataTask.eventData = sendOnceSample
m.AnalyticsDataTask.eventData = {
requestType: analyticsRequestType
requestData: sendOnceSample
isSsaiRelated: isCurrentSampleSsaiRelated()
}

sendAnalyticsRequest()
end sub

sub sendAnalyticsSampleOnce(analyticsSample, analyticsRequestType = m.AnalyticsRequestTypes.REGULAR)
m.AnalyticsDataTask.eventData = {
requestType: analyticsRequestType,
requestData: analyticsSample,
isSsaiRelated: isCurrentSampleSsaiRelated()
}

sendAnalyticsRequest()
end sub
Expand Down
2 changes: 2 additions & 0 deletions collectorCore/collectorCore.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
<function name="adBreakStart"/>
<function name="adStart"/>
<function name="adBreakEnd"/>
<function name="adQuartileFinished"/>
<function name="onError"/>
<field id="playerState" alias="analyticsDataTask.playerState" type="string"/>
<field id="fireHeartbeat" type="boolean" alwaysnotify="true"/>
</interface>
Expand Down
1 change: 1 addition & 0 deletions collectorCore/collectorCoreConfig.brs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ function getCollectorCoreConfig()
return {
serviceEndpoints: {
analyticsData: "https://analytics-ingress-global.bitmovin.com/analytics"
analyticsAdData: "https://analytics-ingress-global.bitmovin.com/analytics/a"
analyticsLicense: "https://analytics-ingress-global.bitmovin.com/licensing"
}
}
Expand Down
10 changes: 10 additions & 0 deletions collectorCore/collectorCoreConstants.brs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ function getAdTypes()
return adTypes
end function

function getAdQuartileTypes()
adQuartileTypes = {
FIRST: "first",
MIDPOINT: "midpoint",
THIRD: "third",
COMPLETED: "completed",
}
return adQuartileTypes
end function

function getCustomDataValueKeys()
customDataValuesKeys = [
"customData1",
Expand Down
9 changes: 9 additions & 0 deletions collectorCore/collectorCoreUtils.brs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ end function
function isArray(v)
return getInterface(v, "ifArray") <> invalid
end function

function getAnalyticsRequestTypes()
analyticsRequestTypes = {
REGULAR: 0,
AD_ENGAGEMENT: 1
}

return analyticsRequestTypes
end function
Loading

0 comments on commit 7aa34fc

Please sign in to comment.