Skip to content

Commit e2f099d

Browse files
authored
v1.7.0 (#63)
* fix renditionchange for demuxed content, reduce overall rendezvous for RAF use cases, and update expected raf callback * comment fix * add support for `useSSAI` * beta 1 tag * fix adplay and adplaying for SSAI adbreakstart
1 parent 18e2282 commit e2f099d

File tree

4 files changed

+113
-61
lines changed

4 files changed

+113
-61
lines changed

sampleapp_source/components_recycled/components/MuxTask.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<field id="view" type="String" alwaysNotify="true"/>
88
<field id="exit" type="Boolean" alwaysNotify="true"/>
99
<field id="useRenderStitchedStream" type="String" alwaysNotify="true" value="false"/>
10+
<field id="useSSAI" type="String" alwaysNotify="true" value="false"/>
1011
</interface>
1112
<script type="text/brightscript" uri="pkg:/libs/mux-analytics.brs"/>
1213
</component>

sampleapp_source/components_reset/components/MuxTask.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
<field id="view" type="String" alwaysNotify="true"/>
88
<field id="exit" type="Boolean" alwaysNotify="true"/>
99
<field id="exitType" type="String" alwaysNotify="true" value="hard"/>
10-
<field id="useRenderStitchedStream" type="String" alwaysNotify="true" value="true"/>
10+
<field id="useRenderStitchedStream" type="String" alwaysNotify="true" value="false"/>
11+
<field id="useSSAI" type="String" alwaysNotify="true" value="false"/>
1112
</interface>
1213
<script type="text/brightscript" uri="pkg:/libs/mux-analytics.brs"/>
1314
</component>

sampleapp_source/components_reset/components/PlayerTask.brs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ sub playContent()
9797
m.top.video.content = contentNode
9898
PlayContentOnlyNoAds(contentInfo)
9999
else if selectionId = "dashnoads"
100-
contentNode.URL = "http://rdmedia.bbc.co.uk/dash/ondemand/bbb/2/client_manifest-common_init.mpd"
100+
contentNode.URL = "https://dash.akamaized.net/dash264/TestCases/5a/nomor/1.mpd"
101101
contentNode.StreamFormat = "dash"
102-
contentNode.length = 572
103-
contentInfo.length = 568
102+
contentNode.length = 594
103+
contentInfo.length = 594
104104
contentInfo.contentId = "BIG BUCK BUNNY"
105105
m.top.video.content = contentNode
106106
PlayContentOnlyNoAds(contentInfo)
@@ -278,7 +278,10 @@ end sub
278278

279279
sub adTrackingCallback(obj = Invalid as Dynamic, eventType = Invalid as Dynamic, ctx = Invalid as Dynamic)
280280
mux = GetGlobalAA().global.findNode("mux")
281-
mux.setField("rafEvent", {obj:obj, eventType:eventType, ctx:ctx})
281+
if obj <> Invalid
282+
adUrl = obj.getAdUrl()
283+
end if
284+
mux.setField("rafEvent", {obj: { adurl: adUrl }, eventType:eventType, ctx:ctx})
282285
end sub
283286

284287
sub playVideoWithAds(adPods as object, adIface as object) as void

src/mux-analytics.brs

Lines changed: 103 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
sub init()
2-
m.MUX_SDK_VERSION = "1.6.0"
2+
m.MUX_SDK_VERSION = "1.7.0"
33
m.top.id = "mux"
44
m.top.functionName = "runBeaconLoop"
55
end sub
@@ -85,6 +85,11 @@ function runBeaconLoop()
8585
end if
8686
m.top.ObserveField("useRenderStitchedStream", m.messagePort)
8787

88+
if m.top.useSSAI <> Invalid
89+
m.mxa.useSSAIHandler(m.top.useSSAI)
90+
end if
91+
m.top.ObserveField("useSSAI", m.messagePort)
92+
8893
if m.top.error <> Invalid
8994
m.mxa.videoErrorHandler(m.top.error)
9095
end if
@@ -102,7 +107,7 @@ function runBeaconLoop()
102107
while running
103108
exitMsg = wait(10, m.exitPort)
104109
msg = wait(40, m.messagePort)
105-
if exitMsg <> invalid
110+
if exitMsg <> Invalid
106111
data = exitMsg.getData()
107112
if data = true
108113
running = false
@@ -133,6 +138,8 @@ function runBeaconLoop()
133138
m.mxa.configChangeHandler(msg.getData())
134139
else if field = "useRenderStitchedStream"
135140
m.mxa.useRenderStitchedStreamHandler(msg.getData())
141+
else if field = "useSSAI"
142+
m.mxa.useSSAIHandler(msg.getData())
136143
else if field = "error"
137144
m.mxa.videoErrorHandler(msg.getData())
138145
else if field = "control"
@@ -386,6 +393,7 @@ function muxAnalytics() as Object
386393
m._Flag_isSeeking = false
387394
m._Flag_lastReportedPosition = 0
388395
m._Flag_FailedAdsErrorSet = false
396+
m._Flag_useSSAI = false
389397

390398
' Flags specifically for when renderStitchedStream is used
391399
m._Flag_useRenderStitchedStream = false
@@ -603,29 +611,33 @@ function muxAnalytics() as Object
603611

604612
prototype.videoStreamingSegmentChangeHandler = sub(videoSegment as object)
605613
if videoSegment <> Invalid
606-
if m._lastPlayerWidth <> Invalid AND m._lastPlayerHeight <> Invalid AND m._lastPlayheadPosition <> Invalid AND m._lastSourceWidth <> Invalid AND m._lastSourceHeight <> Invalid AND videoSegment.segStartTime <> Invalid
607-
player_playhead_time = Int(videoSegment.segStartTime * 1000)
608-
if m._lastPlayerWidth >= 0 AND m._lastPlayerHeight >= 0 AND m._lastPlayheadPosition >= 0 AND player_playhead_time >= 0 AND m._lastSourceWidth > 0 AND m._lastSourceHeight > 0
609-
timeDiff = player_playhead_time - m._lastPlayheadPosition
610-
scale = m._min(m._lastPlayerWidth / m._lastSourceWidth, m._lastPlayerHeight / m._lastSourceHeight)
611-
upscale = m._max(0, scale - 1)
612-
downscale = m._max(0, 1 - scale)
613-
m._viewMaxUpscalePercentage = m._max(m._viewMaxUpscalePercentage, upscale)
614-
m._viewMaxDownscalePercentage = m._max(m._viewMaxDownscalePercentage, downscale)
615-
m._viewTotalContentPlaybackTime = m._safeAdd(m._viewTotalContentPlaybackTime, timeDiff)
616-
m._viewTotalUpscaling = m._safeAdd(m._viewTotalUpscaling, upscale * timeDiff)
617-
m._viewTotalDownscaling = m._safeAdd(m._viewTotalDownscaling, downscale * timeDiff)
614+
' For now, we only listen for video or media segments for all of our calculations
615+
if videoSegment.segType = 0 or videoSegment.segType = 2
616+
if m._lastPlayerWidth <> Invalid AND m._lastPlayerHeight <> Invalid AND m._lastPlayheadPosition <> Invalid AND m._lastSourceWidth <> Invalid AND m._lastSourceHeight <> Invalid AND videoSegment.segStartTime <> Invalid
617+
player_playhead_time = Int(videoSegment.segStartTime * 1000)
618+
if m._lastPlayerWidth >= 0 AND m._lastPlayerHeight >= 0 AND m._lastPlayheadPosition >= 0 AND player_playhead_time >= 0 AND m._lastSourceWidth > 0 AND m._lastSourceHeight > 0
619+
timeDiff = player_playhead_time - m._lastPlayheadPosition
620+
scale = m._min(m._lastPlayerWidth / m._lastSourceWidth, m._lastPlayerHeight / m._lastSourceHeight)
621+
upscale = m._max(0, scale - 1)
622+
downscale = m._max(0, 1 - scale)
623+
m._viewMaxUpscalePercentage = m._max(m._viewMaxUpscalePercentage, upscale)
624+
m._viewMaxDownscalePercentage = m._max(m._viewMaxDownscalePercentage, downscale)
625+
m._viewTotalContentPlaybackTime = m._safeAdd(m._viewTotalContentPlaybackTime, timeDiff)
626+
m._viewTotalUpscaling = m._safeAdd(m._viewTotalUpscaling, upscale * timeDiff)
627+
m._viewTotalDownscaling = m._safeAdd(m._viewTotalDownscaling, downscale * timeDiff)
628+
end if
618629
end if
619-
end if
620-
if videoSegment.width <> Invalid AND videoSegment.height <> Invalid AND videoSegment.segBitrateBps <> Invalid
621-
if m._lastSourceWidth <> Invalid AND m._lastSourceWidth <> videoSegment.width OR m._lastSourceHeight <> Invalid AND m._lastSourceHeight <> videoSegment.height OR m._lastVideoSegmentBitrate <> Invalid AND m._lastVideoSegmentBitrate <> videoSegment.segBitrateBps
622-
m._addEventToQueue(m._createEvent("renditionchange", { video_source_width : videoSegment.width, video_source_height : videoSegment.height, video_source_bitrate : videoSegment.segBitrateBps }))
630+
if videoSegment.width <> Invalid AND videoSegment.height <> Invalid AND videoSegment.segBitrateBps <> Invalid
631+
if m._lastSourceWidth <> Invalid AND m._lastSourceWidth <> videoSegment.width OR m._lastSourceHeight <> Invalid AND m._lastSourceHeight <> videoSegment.height OR m._lastVideoSegmentBitrate <> Invalid AND m._lastVideoSegmentBitrate <> videoSegment.segBitrateBps
632+
details = { video_source_width : videoSegment.width, video_source_height : videoSegment.height, video_source_bitrate : videoSegment.segBitrateBps }
633+
m._addEventToQueue(m._createEvent("renditionchange", details))
634+
end if
623635
end if
636+
m._lastSourceWidth = videoSegment.width
637+
m._lastSourceHeight = videoSegment.height
638+
m._lastVideoSegmentBitrate = videoSegment.segBitrateBps
639+
m._lastPlayheadPosition = Int(videoSegment.segStartTime * 1000)
624640
end if
625-
m._lastSourceWidth = videoSegment.width
626-
m._lastSourceHeight = videoSegment.height
627-
m._lastVideoSegmentBitrate = videoSegment.segBitrateBps
628-
m._lastPlayheadPosition = Int(videoSegment.segStartTime * 1000)
629641
end if
630642
end sub
631643

@@ -645,8 +657,10 @@ function muxAnalytics() as Object
645657
props.request_type = "captions"
646658
end if
647659
end if
660+
if videoSegment.segDuration <> Invalid
661+
props.request_media_duration = videoSegment.segDuration
662+
end if
648663
if videoSegment.downloadDuration <> Invalid
649-
props.request_media_duration = videoSegment.downloadDuration
650664
date = m._getDateTime()
651665
now = 0# + date.AsSeconds() * 1000.0# + date.GetMilliseconds()
652666
props.request_response_end = FormatJson(now)
@@ -716,6 +730,12 @@ function muxAnalytics() as Object
716730
end if
717731
end sub
718732

733+
prototype.useSSAIHandler = sub(useSSAI as String)
734+
if useSSAI <> Invalid
735+
m._Flag_useSSAI = (useSSAI = "true")
736+
end if
737+
end sub
738+
719739
prototype.videoErrorHandler = sub(error as Object)
720740
errorCode = "0"
721741
errorMessage = "Unknown"
@@ -730,7 +750,7 @@ function muxAnalytics() as Object
730750
if error.errorMessage <> Invalid
731751
errorMessage = error.errorMessage
732752
end if
733-
if error.errorContext <> invalid
753+
if error.errorContext <> Invalid
734754
errorContext = error.errorContext
735755
end if
736756
end if
@@ -740,24 +760,47 @@ function muxAnalytics() as Object
740760
prototype.rafEventHandler = sub(rafEvent)
741761
data = rafEvent.getData()
742762
eventType = data.eventType
763+
obj = data.obj
764+
ctx = data.ctx
765+
766+
' Only pull the pieces of data we care about
767+
' Previous instructions passed the full adIface in, which has a circular reference in some cases
768+
adMetadata = {}
769+
if obj <> Invalid
770+
if obj.adurl <> Invalid
771+
adMetadata.adTagUrl = obj.adurl
772+
end if
773+
end if
774+
743775
m._advertProperties = {}
744776

745777
' Special case to handle if `renderStitchedStream` is used or not
746778
if m._Flag_useRenderStitchedStream = true
747-
m._renderStitchedStreamRafEventHandler(eventType, data)
779+
m._renderStitchedStreamRafEventHandler(eventType, ctx, adMetadata)
748780
else
749-
m._rafEventHandler(eventType, data)
781+
m._rafEventHandler(eventType, ctx, adMetadata)
750782
end if
751783
end sub
752784

753-
prototype._rafEventhandler = sub(eventType, data)
785+
prototype._rafEventhandler = sub(eventType, ctx, adMetadata)
754786
m._Flag_isPaused = (eventType = "Pause")
755787
if eventType = "PodStart"
756-
m._advertProperties = m._getAdvertProperites(data.obj)
788+
m._advertProperties = m._getAdvertProperites(adMetadata)
757789
m._addEventToQueue(m._createEvent("adbreakstart"))
790+
' In the case that this is SSAI, we need to signal an adplay and adplaying event
791+
if m._Flag_useSSAI = true
792+
m._addEventToQueue(m._createEvent("adplay"))
793+
m._addEventToQueue(m._createEvent("adplaying"))
794+
end if
758795
else if eventType = "PodComplete"
759796
m._addEventToQueue(m._createEvent("adbreakend"))
760797
m._Flag_FailedAdsErrorSet = false
798+
' In the case that this is SSAI, we need to signal a play and playing event
799+
if m._Flag_useSSAI = true
800+
m._Flag_isPaused = false
801+
m._triggerPlayEvent()
802+
m._addEventToQueue(m._createEvent("playing"))
803+
end if
761804
else if eventType = "Impression"
762805
m._addEventToQueue(m._createEvent("adimpresion"))
763806
else if eventType = "Pause"
@@ -778,11 +821,11 @@ function muxAnalytics() as Object
778821
' CHECK FOR PREROLL
779822
m._viewPrerollPlayedCount++
780823
end if
781-
m._advertProperties = m._getAdvertProperites(data.ctx)
824+
m._advertProperties = m._getAdvertProperites(ctx)
782825
m._addEventToQueue(m._createEvent("adplay"))
783826
m._addEventToQueue(m._createEvent("adplaying"))
784827
else if eventType = "Resume"
785-
m._advertProperties = m._getAdvertProperites(data.ctx)
828+
m._advertProperties = m._getAdvertProperites(ctx)
786829
m._addEventToQueue(m._createEvent("adplay"))
787830
m._addEventToQueue(m._createEvent("adplaying"))
788831
else if eventType = "Complete"
@@ -793,12 +836,12 @@ function muxAnalytics() as Object
793836
' this here for now for context in the future
794837
' errorCode = ""
795838
' errorMessage = ""
796-
' if data.ctx <> Invalid
797-
' if data.ctx.errcode <> Invalid
798-
' errorCode = data.ctx.errcode
839+
' if ctx <> Invalid
840+
' if ctx.errcode <> Invalid
841+
' errorCode = ctx.errcode
799842
' end if
800-
' if data.ctx.errmsg <> Invalid
801-
' errorMessage = data.ctx.errmsg
843+
' if ctx.errmsg <> Invalid
844+
' errorMessage = ctx.errmsg
802845
' end if
803846
' end if
804847
m._addEventToQueue(m._createEvent("aderror"))
@@ -816,10 +859,10 @@ function muxAnalytics() as Object
816859
end if
817860
end sub
818861

819-
prototype._renderStitchedStreamRafEventHandler = sub(eventType, data)
862+
prototype._renderStitchedStreamRafEventHandler = sub(eventType, ctx, adMetadata)
820863
if eventType = "AdStateChange"
821-
state = data.ctx.state
822-
m._advertProperties = m._getAdvertProperites(data.obj)
864+
state = ctx.state
865+
m._advertProperties = m._getAdvertProperites(adMetadata)
823866
if state = "buffering"
824867
' the buffering state is the first event we get in a new ad pod, so start
825868
' our ad break here if we're not already in one
@@ -882,7 +925,7 @@ function muxAnalytics() as Object
882925
else if eventType = "ContentStateChange"
883926
' We really only care about this if we're _not_ in an ad break
884927
if not m._Flag_rssInAdBreak
885-
state = data.ctx.state
928+
state = ctx.state
886929
if state = "buffering"
887930
' if m._Flag_isPaused
888931
m._Flag_isPaused = false
@@ -907,6 +950,7 @@ function muxAnalytics() as Object
907950

908951
prototype.pollingIntervalHandler = sub(pollingIntervalEvent)
909952
if m.video = Invalid then return
953+
if m._Flag_isPaused = true then return
910954

911955
m._setBufferingMetrics()
912956
m._updateContentPlaybackTime()
@@ -1191,7 +1235,7 @@ function muxAnalytics() as Object
11911235
props.viewer_device_manufacturer = deviceInfo.GetModelDetails()["VendorName"]
11921236
' If GetModel() is invalid, try the specific model number
11931237
seriesModel = deviceInfo.GetModel()
1194-
if seriesModel = invalid
1238+
if seriesModel = Invalid
11951239
seriesModel = deviceInfo.GetModelDetails()["ModelNumber"]
11961240
end if
11971241
props.viewer_device_model = seriesModel
@@ -1238,7 +1282,7 @@ function muxAnalytics() as Object
12381282
' Set called per video content'
12391283
prototype._getVideoContentProperties = function(incomingContent as Object) as Object
12401284
props = {}
1241-
if incomingContent <> invalid
1285+
if incomingContent <> Invalid
12421286
content = incomingContent.GetFields()
12431287
if content.title <> Invalid AND (type(content.title) = "String" OR type(content.title) = "roString") AND content.title <> ""
12441288
props.video_title = content.title
@@ -1298,12 +1342,15 @@ function muxAnalytics() as Object
12981342
prototype._getAdvertProperites = function(adData as Object) as Object
12991343
props = {}
13001344
if adData <> Invalid
1301-
if adData.ad <> Invalid
1302-
if adData.adIndex <> Invalid AND adData.adIndex = 1 'preroll only'
1303-
if adData.ad.streams <> Invalid
1304-
if adData.ad.streams.count() > 0
1305-
if adData.ad.streams[0].url <> Invalid
1306-
adUrl = adData.ad.streams[0].url
1345+
ad = adData.ad
1346+
adIndex = adData.adIndex
1347+
adTagUrl = adData.adTagUrl
1348+
if ad <> Invalid
1349+
if adIndex <> Invalid AND adIndex = 1 'preroll only'
1350+
if ad.streams <> Invalid
1351+
if ad.streams.count() > 0
1352+
if ad.streams[0].url <> Invalid
1353+
adUrl = ad.streams[0].url
13071354
if adUrl <> Invalid AND adUrl <> ""
13081355
props.view_preroll_ad_asset_hostname = m._getHostname(adUrl)
13091356
props.view_preroll_ad_asset_domain = m._getDomain(adUrl)
@@ -1313,9 +1360,9 @@ function muxAnalytics() as Object
13131360
end if
13141361
end if
13151362
end if
1316-
if adData.adurl <> Invalid AND adData.adurl <> ""
1317-
props.view_preroll_ad_tag_hostname = m._getHostname(adData.adurl)
1318-
props.view_preroll_ad_tag_domain = m._getDomain(adData.adurl)
1363+
if adTagUrl <> Invalid AND adTagUrl <> ""
1364+
props.view_preroll_ad_tag_hostname = m._getHostname(adTagUrl)
1365+
props.view_preroll_ad_tag_domain = m._getDomain(adTagUrl)
13191366
end if
13201367
end if
13211368
return props
@@ -1436,7 +1483,7 @@ function muxAnalytics() as Object
14361483
playerInitTime = m._configProperties.player_init_time
14371484
end if
14381485

1439-
if playerInitTime <> invalid
1486+
if playerInitTime <> Invalid
14401487
if playerInitTime > 0
14411488
props.player_startup_time = Int(m._startTimestamp - playerInitTime)
14421489
if m._viewTimeToFirstFrame <> Invalid AND m._viewTimeToFirstFrame <> 0
@@ -1930,8 +1977,8 @@ function muxAnalytics() as Object
19301977
' ' //////////////////////////////////////////////////////////////
19311978

19321979
prototype._min = function(a, b) as object
1933-
if a = invalid then a = 0
1934-
if b = invalid then b = 0
1980+
if a = Invalid then a = 0
1981+
if b = Invalid then b = 0
19351982

19361983
if a < b then
19371984
return a
@@ -1941,8 +1988,8 @@ function muxAnalytics() as Object
19411988
end function
19421989

19431990
prototype._max = function(a, b) as object
1944-
if a = invalid then a = 0
1945-
if b = invalid then b = 0
1991+
if a = Invalid then a = 0
1992+
if b = Invalid then b = 0
19461993

19471994
if a < b then
19481995
return b
@@ -1952,7 +1999,7 @@ function muxAnalytics() as Object
19521999
end function
19532000

19542001
prototype._safeAdd = function(var, addValue) as object
1955-
if var = invalid then
2002+
if var = Invalid then
19562003
return addValue
19572004
else
19582005
return var + addValue

0 commit comments

Comments
 (0)