RAF not correctly determining ad pods from VMAP

We’re seeing an issue where the ad pods returned from RAF.getAds() do not match the VMAP in the ad URL provided to RAF via setAdUrl().

Background: we’re using using SSAI in a RSG app.

Details:
When we look at the VMAP for the ad URL, we see, for example, two midrolls, with timeOffets:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<vmap:VMAP xmlns:vmap="http://www.iab.net/videosuite/vmap version="1.0.1">
    <vmap:AdBreak timeOffset="00:05:35.368" breakType="linear" breakId="1">
        <vmap:AdSource>
            <vmap:VASTAdData>
                <VAST version="3.0">
                    <Ad id="19585946" sequence="1">
                        <InLine>
                            <AdSystem>FreeWheel</AdSystem>
...
   </vmap:AdBreak>
    <vmap:AdBreak timeOffset="00:11:00.994" breakType="linear" breakId="2">
        <vmap:AdSource>
            <vmap:VASTAdData>
                <VAST version="3.0">
                    <Ad id="19585946" sequence="1">
                        <InLine>
                            <AdSystem>FreeWheel</AdSystem>
...

However the ad pods returned from RAF.getAds() shows (generally) only one preroll.
e.g.

<Component: roAssociativeArray> =
{
    ads: <Component: roArray>
    backfilled: true
    duration: 30
    rendersequence: "preroll"
    rendertime: 0
    slots: 0
    tracking: <Component: roArray>
    viewed: false
}

Note that sometimes the returned ad pods contains both ads, with the correct render times.

This is an outline of our workflow, running in a player task node:

adInterface.setAdUrl(adURL)

adPods = adInterface.getAds()

adInterface.stitchedAdsInit(adPods)

...
while keepPlaying
  videoMsg = wait(500, port)
  curAd = adInterface.stitchedAdHandledEvent(videoMsg, { sgNode: videoNode, port: port })
  ...
end while

This is a problem for us since the RAF’s ad handling (e.g. “Ad 1 of 1”) and player control blocking will occur at the wrong time.

Ideas?

how are you providing a Freewheel URL when using SSAI? The results from 2 different ad requests can differ, right?

Adobe Auditude is generating the ad URL for us – this is what’s provided to RAF via setAdUrl().
Auditude service is also stitching in the ads (correctly) into a new stream, which we’re playing.

We are examining different ad requests (some that RAF correctly determines the ad pods from, and some that it doesn’t) to try and spot the differences. But so far we haven’t found any clues – the VMAPs appear valid for both.

“acreskey” wrote:
This is a problem for us since the RAF’s ad handling (e.g. “Ad 1 of 1”) and player control blocking will occur at the wrong time.
Have you accounted for this detail - that for SSAI, stitchedAdsInit() expects time offsets from the stream start and not the break start?
stitchedAdsInit()” wrote:
… In particular, for server-stitched ads, all time-dependent tracking beacons (Impression and quartile beacons) must have a valid time data member set, with a value relative to the entire stitched stream. For example, if a 30-second ad starts at 10:00 within the stitched stream, its Impression beacons should have track.time = 600.0 and its Midpoint beacons should have track.time = 615.0, and so on. …
Also, where do you get the VMAP from? If it’s from source before the stitching server, consider that the stitching process introduces some delays/extra frames, so the break pauses would diverge from VMAP from a separate ad server.

“acreskey” wrote:
Adobe Auditude is generating the ad URL for us – this is what’s provided to RAF via setAdUrl().
Auditude service is also stitching in the ads (correctly) into a new stream, which we’re playing.
I get that, but the problem is that Adobe makes one FW request for their backend system, and you make another from the device. You could hit a situation where ad inventory is available for Adobe’s request, then exhausted when the device makes the same request.
In our implementation of Adobe SSAI, we are provided with the VMAP response that Adobe gets from Freewheel and provide the data to RAF using stitchedAdsInit(). We never call setAdUrl() with SSAI.

“RokuNB” wrote:

“acreskey” wrote:
This is a problem for us since the RAF’s ad handling (e.g. “Ad 1 of 1”) and player control blocking will occur at the wrong time.
Have you accounted for this detail - that for SSAI, stitchedAdsInit() expects time offsets from the stream start and not the break start?
stitchedAdsInit()” wrote:
… In particular, for server-stitched ads, all time-dependent tracking beacons (Impression and quartile beacons) must have a valid time data member set, with a value relative to the entire stitched stream. For example, if a 30-second ad starts at 10:00 within the stitched stream, its Impression beacons should have track.time = 600.0 and its Midpoint beacons should have track.time = 615.0, and so on. …

Also, where do you get the VMAP from? If it’s from source before the stitching server, consider that the stitching process introduces some delays/extra frames, so the break pauses would diverge from VMAP from a separate ad server.
Thank you for the quick reply RokuNB.

Although I’m new to VMAP and VAST, it does appear that the time-dependent tracking beacons in the VMAP do have their time set relative to the entire stitched stream.
At least if RAF uses the ‘tpos’ field.
For example, here we have the AdBreak at 5:35, and I’m seeing and events with tpos=335

    <vmap:AdBreak timeOffset="00:05:35.368" breakType="linear" breakId="1">
        <vmap:AdSource>
            <vmap:VASTAdData>
                <VAST version="3.0">
                    <Ad id="19585946" sequence="1">
                        <InLine>
                            <AdSystem>FreeWheel</AdSystem>
                            <AdTitle>....</AdTitle>
                            <Impression>http://bea4.v.fwmrm.net/ad/l/1?s=d001&n=48804%3B48804%3B381963&t=1499795079091200015&f=&r=48804&adid=19585946&reid=7250158&arid=0&auid=&cn=defaultImpression&et=i&_cc=19585946,7250158,,,1499795079,1&tpos=335&iw=&uxnw=&uxss=&uxct=&metr=1031&init=1&vcid2=48804%3Af2c022b54b07596779cc00c4a7e26e49&asid=-1&ssid=1954993&cr=https%3A//servedby.flashtalking.com/imp/8/78463%3B2547733%3B201%3Bpixel%3BTurner%3BTurnerConnectedTV301x1/%3Fcachebuster%3D700020434</Impression>
                            <Impression>http://ad.auditude.com/adserver/e?type=adimp&a=342240&w=17&uid=0gCR6cUlSMWpsa74nrYlXQ&s=2b595733&t=1499795079&u=ac217921a4a853e52310ebc459eef367&z=131829&cid=324172756&br=1&pod=id:1,ctype:l,ptype:p,dur:200,lot:1,cpos:1&ax=0,0,0,0&sq=1</Impression>
                            <Creatives>
                                <Creative AdID="19585946">
                                    <Linear>
                                        <Duration>00:00:30.030</Duration>
                                        <TrackingEvents>
                                            <Tracking event="creativeView">http://ad.auditude.com/adserver/i/;uid=0gCR6cUlSMWpsa74nrYlXQ;s=2b595733;t=1499795079;u=ac217921a4a853e52310ebc459eef367;z=131829;cid=324172756;br=1;pod=id:1,ctype:l,ptype:p,dur:200,lot:1,cpos:1;ax=0,0,0,0;sq=1;a1=105;a=342240;w=17/c0x0</Tracking>
                                            <Tracking event="start">http://ad.auditude.com/adserver/e?type=AD_PROGRESS&a=342240&a1=105&ref=urn:asset:342240:105&unit=percent&progress=0&uid=0gCR6cUlSMWpsa74nrYlXQ&s=2b595733&t=1499795079&u=ac217921a4a853e52310ebc459eef367&z=131829&cid=324172756&br=1&pod=id:1,ctype:l,ptype:p,dur:200,lot:1,cpos:1&ax=0,0,0,0&sq=1</Tracking>
                                            <Tracking event="firstQuartile">http://bea4.v.fwmrm.net/ad/l/1?s=d001&n=48804%3B48804%3B381963&t=1499795079091200015&f=&r=48804&adid=19585946&reid=7250158&arid=0&auid=&cn=firstQuartile&et=i&_cc=&tpos=335&init=1&iw=&uxnw=&uxss=&uxct=&metr=1031</Tracking>
                                            <Tracking event="firstQuartile">http://ad.auditude.com/adserver/e?type=AD_PROGRESS&a=342240&a1=105&ref=urn:asset:342240:105&unit=percent&progress=25&uid=0gCR6cUlSMWpsa74nrYlXQ&s=2b595733&t=1499795079&u=ac217921a4a853e52310ebc459eef367&z=131829&cid=324172756&br=1&pod=id:1,ctype:l,ptype:p,dur:200,lot:1,cpos:1&ax=0,0,0,0&sq=1</Tracking>
                                            <Tracking event="midpoint">http://bea4.v.fwmrm.net/ad/l/1?s=d001&n=48804%3B48804%3B381963&t=1499795079091200015&f=&r=48804&adid=19585946&reid=7250158&arid=0&auid=&cn=midPoint&et=i&_cc=&tpos=335&init=1&iw=&uxnw=&uxss=&uxct=&metr=1031</Tracking>
                                            <Tracking event="midpoint">http://ad.auditude.com/adserver/e?type=AD_PROGRESS&a=342240&a1=105&ref=urn:asset:342240:105&unit=percent&progress=50&uid=0gCR6cUlSMWpsa74nrYlXQ&s=2b595733&t=1499795079&u=ac217921a4a853e52310ebc459eef367&z=131829&cid=324172756&br=1&pod=id:1,ctype:l,ptype:p,dur:200,lot:1,cpos:1&ax=0,0,0,0&sq=1</Tracking>
                                            

The VMAP is returned from the Auditude stitching server, so we are expecting it to be account for the extra frames. But the issue we’re seeing is not that the Ad UI is rendered at a different time, it’s that while we see two ad breaks in the VMAP, only one ad pod is generally found, and it’s always rendered as a pre-roll.

“tim_beynart” wrote:

“acreskey” wrote:
Adobe Auditude is generating the ad URL for us – this is what’s provided to RAF via setAdUrl().
Auditude service is also stitching in the ads (correctly) into a new stream, which we’re playing.
I get that, but the problem is that Adobe makes one FW request for their backend system, and you make another from the device. You could hit a situation where ad inventory is available for Adobe’s request, then exhausted when the device makes the same request.
In our implementation of Adobe SSAI, we are provided with the VMAP response that Adobe gets from Freewheel and provide the data to RAF using stitchedAdsInit(). We never call setAdUrl() with SSAI.
I see what you mean, Tim - thanks for the reply.
So you’re generating your own ad pod array from the original VMAP and feeding it directly into RAF.
That goes against our implementation guideline, so I’m hoping to avoid that.

Actually we never see the original VMAP response, we get an Adobe-defined JSON file with all the ad break information and beacons. This is part of the Adobe SSAI API we use.

But frankly I don’t see how you will ever have accurate ad data if you are making 2 requests to Freewheel, so hopefully I am misunderstanding your problem.

“acreskey” wrote:
That goes against our implementation guideline, so I’m hoping to avoid that.
I’m curious what guidelines you refer to. I’ve been using Adobe SSAI on Roku for over 2 years and your approach doesn’t sound familiar. We worked closely with them to implement SSAI.

“tim_beynart” wrote:
Actually we never see the original VMAP response, we get an Adobe-defined JSON file with all the ad break information and beacons. This is part of the Adobe SSAI API we use.

But frankly I don’t see how you will ever have accurate ad data if you are making 2 requests to Freewheel, so hopefully I am misunderstanding your problem.
We’re not making 2 requests to Freewheel – one request to Auditude gives us the stitched ad stream, and a second (based on the first) supplies us with the VMAP (presumably the one that was used to stitch in the ads).
But our organization’s guidance is to provide this VMAP to RAF to parse into ad pods. (Which I believe RAF should handle, according to the docs).

OK that makes sense. Our implementation is similar, but we do not get the raw VMAP XML from Adobe, we get a JSON translation. Which we then translate into the RAF-friendly ad pods format.

I did notice this log output from RAF when the ad pods are not returned:

RAF 2.0108; empty response: 

Roku_Ads_util_getStringFromUrl: requesting URL: http://pubads.g.doubleclick.net/gampad/ads?slotname=/82114269/rrafcs/bf/dev&sz=1920x1080&tfcd=0&url=http://roku.com&unviewed_position_start=1&output=vast&impl=s&env=vp&gdfp_req=1&ad_rule=0&description_url=http%3A%2F%2Fapps.roku.com&vad_type=linear&nofb=0&sdkv=roku&min_ad_duration=0&max_ad_duration=60000&rdid=971ccf63-9e60-53c3-b2ad-5403bb5f299a&is_lat=0&idtype=rida&correlator=1499806025110&scor=1499806025110&pod=POD_NUM&ppos=POD_POSITION&cust_params=genre%3DROKU_ADS_CONTENT_GENRE%26ua%3DRoku%252FDVP-7.70%2520%2528047.70E04093A%2529%26ai%3Ddev

Although I do actually get a response when I manually request that URL.

It looks like it’s timing… if I call adPods = adInterface.getAds() after a small time delay, the correct ad pods are found.
Interesting!

“acreskey” wrote:
The VMAP is returned from the Auditude stitching server, so we are expecting it to be account for the extra frames. But the issue we’re seeing is not that the Ad UI is rendered at a different time, it’s that while we see two ad breaks in the VMAP, only one ad pod is generally found, and it’s always rendered as a pre-roll.
That is a really strange thing if happening - mid-roll with a properly set offset (e.g. <vmap:AdBreak timeOffset=“00:05:35.368” …>) somehow turning into a pre-roll. I’d like to know more on this if indeed is happening. (Like capture the VMAP that does that - and btw for test purposes you can do raf.setAdUrl() to a local file, say in tmp:/ or pkg:/ - then you can print formatJson(raf.getAds()) )

Thank you RokuNB for the debugging technique.

So what was happening was that Auditude provided me with a URL for the VMAP that wasn’t actually ready. If I requested that VMAP immediately (i.e. the next line of code), it would most often fail.
So basically I was providing RAF with an invalid ad URL.

Because the default RAF ad prefs are set to backfill ads, RAF was making its own ad request against the Roku default ad service (hence the “preroll” ad pod).

So I’ve disabled the backfill of ads and I have to poll the VMAP URL until it’s valid.

Thanks for the help.

TL;DR: RAF did not actually have any issues in determining ad pods from a valid VMAP. If you provide an invalid URL the default behaviour is to backfill with Roku ad service ads.

Good catch, it took me quite a while to figure out that RAF backfills ads by default. This caused quite a bit of head scratching and some conspiracy theories.
IMHO backfill should be opt-in, not opt-out.
For anyone else reading this thread, include the following line to turn off backfill ads:

'disable roku's backfill ads
adIface.setAdPrefs(false,0)

“acreskey” wrote:
So what was happening was that Auditude provided me with a URL for the VMAP that wasn’t actually ready. If I requested that VMAP immediately (i.e. the next line of code), it would most often fail. So basically I was providing RAF with an invalid ad URL.

Because the default RAF ad prefs are set to backfill ads,  RAF was making its own ad request against the Roku default ad service (hence the “preroll” ad pod). So I’ve disabled the backfill of ads and I have to poll the VMAP URL until it’s valid. Thanks for the help.

TL;DR: RAF did not actually have any issues in determining ad pods from a valid VMAP. If you provide an invalid URL the default behaviour is to backfill with Roku ad service ads.
Wow, i can only try to imagine how confusing that is. And thanks for explaining what the cause was. Indeed turn off backfill (at least for development) and… why is Auditude providing non-ready VMAP? What’s the logic behind?! There must be some way that can be tuned up…

We had this same issue.
With Auditude, you must always make a request to your m3u8 BEFORE the VMAP in order for the VMAP to return.