ערכות IMA SDK מאפשרות לכם לשלב בקלות מודעות מולטימדיה באתרים ובאפליקציות שלכם. ערכות IMA SDK יכולות לבקש מודעות מכל שרת מודעות שתואם ל-VAST ולנהל את הפעלת המודעות באפליקציות שלכם. בעזרת ערכות IMA DAI SDK, אפליקציות בקשה לשידור וידאו של מודעה ותוכן – VOD או תוכן בשידור חי. לאחר מכן ה-SDK מחזיר סטרימינג משולב של מודעות וידאו, כך שלא יהיה צורך לנהל את המעבר בין מודעות וידאו בתוכן בתוך האפליקציה.
איך בוחרים את פתרון DAI שמעניין אתכם
המדריך הזה מדגים איך מפעילים Pod של DAI להצגת מודעות בשידור חי או ב-VOD, באמצעות IMA DAI SDK ל-Roku.
סקירה כללית בנושא הצגת מודעות Pod של IMA DAI
כדי להטמיע הצגת Pod באמצעות IMA DAI יש שני רכיבים עיקריים של SDK: שמודגמים במדריך זה:
StreamRequest.createPodLiveStreamRequest()
/StreamRequest.createPodVodStreamRequest()
: יצירת אובייקט שמגדיר בקשה של מקור נתונים לפרסום של Google שרתים. הבקשות האלה מציינות קוד רשת ו-Pod Live. הפרמטרima.StreamRequest
מחייב גם מפתח נכס מותאם אישית, ואופציונלי API key.StreamManager
: אובייקט שמטפל בתקשורת בין שידור הווידאו לבין IMA DAI SDK, למשל הפעלת פינגים למעקב והעברת אירועי סטרימינג אל מו"ל.
בנוסף, צריך לשלוח בקשה למניפולציה של המניפסט כדי לאחזר את השידור. מניפסט להצגה באפליקציה. התהליך המדויק עשוי להשתנות בהתאם לטכנולוגיית הווידאו שותף (VTP) ל-VTP.
דרישות מוקדמות
- מומלץ לקרוא את התאימות שלנו כדי לוודא יש תמיכה בתרחיש לדוגמה המיועד.
- מורידים את נגן לדוגמה של Roku .
- פורסים את קוד הנגן לדוגמה במכשיר Roku כדי לוודא הגדרת הפיתוח עובדת.
הפעלת הסרטון
את הסרטון לדוגמה נגן מספקת הפעלת סרטון תוכן מחוץ לקופסה. פורסים את הנגן לדוגמה מכשיר Roku כדי לוודא שסביבת הפיתוח מוגדרת כראוי.
הפיכת נגן הווידאו שלך לנגן סטרימינג של IMA DAI
כדי להטמיע נגן סטרימינג, מבצעים את השלבים הבאים.
יצירת Sdk.xml
מוסיפים לפרויקט קובץ חדש בשם MainScene.xml
בשם Sdk.xml
, וגם
מוסיפים את התבנית הבאה:
Sdk.xml
<?xml version = "1.0" encoding = "utf-8" ?>
<component name = "imasdk" extends = "Task">
<interface>
</interface>
<script type = "text/brightscript">
<![CDATA[
' Your code goes here.
]]>
</script>
</component>
צריך לערוך את שני הקבצים האלה (MainScene.xml
וגם Sdk.xml
) לאורך כל הקובץ
במדריך הזה.
טעינת המסגרת של IMA DAI SDK
כדי לטעון את ה-framework, צריך להוסיף את הפרטים הבאים ל-manifest
ול-Sdk.xml
:
מניפסט
bs_libs_required=googleima3
Sdk.xml
<?xml version = "1.0" encoding = "utf-8" ?>
<component name = "imasdk" extends = "Task">
<interface>
</interface>
<script type = "text/brightscript">
<![CDATA[
Library "IMA3.brs"
]]>
</script>
</component>
אתחול IMA DAI SDK
השלב הראשון לטעינת הזרם 'הטמעת מודעות דינמיות של IMA' הוא טעינה להפעיל את IMA DAI SDK. הקוד הבא מפעיל את הסקריפט IMA DAI SDK.
Sdk.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="IMASDKTask" extends="Task">
<interface>
<field id="IMASDKInitialized" type="Boolean" />
<field id="errors" type="stringarray" />
</interface>
<script type = "text/brightscript">
<![CDATA[
Library "IMA3.brs"
sub init()
m.top.functionName = "runThread"
end sub
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
end sub
sub initializeIMASDK()
if m.sdk = invalid
m.sdk = New_IMASDK()
end if
m.top.IMASDKInitialized = true
end sub
]]>
</script>
</component>
עכשיו צריך להתחיל את המשימה הזו בMainScene.xml
ולהסיר את הקריאה לטעינת התוכן
.
MainScene.xml
<?xml version="1.0" encoding="utf-8" ?>
<component extends="Scene" initialFocus="myVideo" name="MainScene">
<script type="text/brightscript">
<![CDATA[
function init()
m.video = m.top.findNode("myVideo")
m.video.notificationinterval = 1
runIMASDKTask()
end function
function runIMASDKTask()
m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
m.IMASDKTask.control = "RUN"
end function
sub handleIMASDKInitialized()
' Follow your manifest manipulator (VTP) documentation to register a user
' streaming session if needed.
end sub
sub handleIMASDKErrors(message as object)
print "------ IMA DAI SDK failed ------"
if message <> invalid and message.getData() <> invalid
print "IMA DAI SDK Error ";message.getData()
end if
end sub
]]>
</script>
<children>
<Video height="720" id="myVideo" visible="false" width="1280"/>
</children>
</component>
יצירת נגן זרם IMA
בשלב הבא, עליך להשתמש במכשיר roVideoScreen
הקיים כדי ליצור שידור IMA
נגן.
הצגת Pod של שידורים חיים
בשידורים חיים, הנגן הזה מיישם שלוש שיטות לקריאה חוזרת (callback):
streamInitialized
, adBreakStarted
וגם adBreakEnded
.
להשבית את הפעלת הטריקים גם כשהשידור נטען. הפעולה הזו מונעת ממשתמשים דילוג על מודעה לפני סרטון ברגע שהיא מתחילה, לפני שההפסקה למודעות התחילה האירוע מופעל.
Sdk.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="IMASDKTask" extends="Task">
<interface>
<field id="IMASDKInitialized" type="Boolean" />
<field id="errors" type="stringarray" />
<field id="urlData" type="assocarray" />
<field id="adPlaying" type="Boolean" />
<field id="videoNode" type="Node" />
</interface>
<script type="text/brightscript">
...
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
setupPlayerCallbacks()
end sub
...
sub initializeIMASDK()
if m.ima = invalid
ima = New_IMASDK()
ima.initSdk()
m.ima = ima
end if
m.top.IMASDKInitialized = true
end sub
sub setupPlayerCallbacks()
m.player = m.ima.createPlayer()
m.player.top = m.top
m.player.streamInitialized = function(urlData)
m.top.videoNode.enableTrickPlay = false
m.top.urlData = urlData
end function
m.player.adBreakStarted = function(adBreakInfo)
print "------ Ad break started ------"
m.top.adPlaying = true
m.top.videoNode.enableTrickPlay = false
end function
m.player.adBreakEnded = function(adBreakInfo)
print "------ Ad break ended ------"
m.top.adPlaying = false
m.top.videoNode.enableTrickPlay = true
end function
end sub
</script>
...
</component>
הצגת Pod של שידורים ב-VOD
בשידורי VOD, נגן הסטרימינג הזה מיישם ארבע שיטות קריאה חוזרת:
streamInitialized
, loadUrl
, adBreakStarted
וגם adBreakEnded
. ב
streamInitialized
מתקשרים חזרה, חשוב להתקשר
StreamManager.loadThirdPartyStream()
. אם לא תעשו זאת, ייעשה שימוש ב-SDK
לא מפעילה את הפונקציה loadUrl
.
בשלב הזה, נבקש ממך גם את כתובת ה-URL של השידור מהשותף הטכנולוגי של הווידאו
(VTP) עם מזהה מקור נתונים שהתקבל ב-loadAdPodStream()
. לאחר מכן, התקשרו
StreamManager.loadThirdPartyStream()
במניפסט של רצף המודעות וב
כתוביות שהוחזרו על ידי ה-VTP.
להשבית את הפעלת הטריקים גם כשהשידור נטען. הפעולה הזו מונעת ממשתמשים דילוג על מודעה לפני סרטון ברגע שהיא מתחילה, לפני שההפסקה למודעות התחילה האירוע מופעל.
Sdk.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="IMASDKTask" extends="Task">
<interface>
<field id="IMASDKInitialized" type="Boolean" />
<field id="errors" type="stringarray" />
<field id="adStitchedStreamInfo" type="assocarray" />
<field id="adPlaying" type="Boolean" />
<field id="videoNode" type="Node" />
<field id="streamParameters" type="assocarray" />
</interface>
<script type="text/brightscript">
...
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
setupPlayerCallbacks()
end sub
...
sub initializeIMASDK()
if m.ima = invalid
ima = New_IMASDK()
ima.initSdk()
m.ima = ima
end if
m.top.IMASDKInitialized = true
end sub
sub loadThirdPartyStream(adStitchedManifest as string, subtitleConfig as dynamic)
m.streamManager.loadThirdPartyStream(adStitchedManifest, subtitleConfig)
end sub
sub setupPlayerCallbacks()
m.player = m.ima.createPlayer()
m.player.top = m.top
m.player.streamInitialized = function(urlData)
adStitchedManifest = m.top.streamParameters.VTPManifest.replace("[[STREAMID]]", urlData.streamId)
loadThirdPartyStream(adStitchedManifest, m.top.streamParameters.subtitleConfig)
end function
m.player.loadUrl = function(streamInfo)
m.top.adStitchedStreamInfo = streamInfo
end function
m.player.adBreakStarted = function(adBreakInfo)
print "------ Ad break started ------"
m.top.adPlaying = true
m.top.videoNode.enableTrickPlay = false
end function
m.player.adBreakEnded = function(adBreakInfo)
print "------ Ad break ended ------"
m.top.adPlaying = false
m.top.videoNode.enableTrickPlay = true
end function
end sub
</script>
...
</component>
יצירה והפעלה של בקשה לשידור חי של רצף מודעות או VOD
אחרי שיש לכם נגן סטרימינג, אתם יכולים ליצור ולהפעיל בקשה לשידור.
בדוגמה הזו יש נתונים לגבי מקור נתונים להצגת Pod ששמור ב-
m.testPodServingStream
הצגת Pod של שידורים חיים
באובייקט m.testPodServingStream
, מאחסנים את הפרמטרים ש-Google Ads
המנהל צריך לזהות את מקור הנתונים הרלוונטי, כמו קוד רשת
מפתח נכס בהתאמה אישית. צריך לאחסן גם את כתובת ה-URL של המניפסט שמשמשת לגישה למניפסט
שרת שינוי ועיבוד. במקרה זה, כתובת ה-URL של המניפסט צריכה לכלול את הפרטים הבאים:
מזהה מקור הנתונים מתווסף אחרי החזרת הבקשה לשידור.
כדי שתהיה לכם אפשרות לתמוך ב-AdUI, כמו הסמלים של בחירות המודעות, עליכם להעביר הפניה לצומת שמכיל את סרטון התוכן שלכם כחלק מהבקשה.
MainScene.xml
function init()
m.video = m.top.findNode("myVideo")
m.video.notificationinterval = 1
m.testPodServingStream = {
title: "Test live stream for DAI Pod Serving",
assetKey: "test-live-stream",
networkCode: "your-network-code",
manifest: "https://.../master.m3u8?stream_id=[[STREAMID]]",
apiKey: ""
}
runIMASDKTask()
end function
function runIMASDKTask()
m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
m.IMASDKTask.streamParameters = m.testPodservingStream
m.IMASDKTask.videoNode = m.video
m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
m.IMASDKTask.control = "RUN"
end function
Sdk.xml
<interface>
<field id="IMASDKInitialized" type="Boolean" />
<field id="errors" type="stringarray" />
<field id="urlData" type="assocarray" />
<field id="adPlaying" type="Boolean" />
<field id="videoNode" type="Node" />
<field id="streamParameters" type="assocarray" />
</interface>
...
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
setupPlayerCallbacks()
loadAdPodStream()
end sub
sub loadAdPodStream()
request = m.ima.CreatePodLiveStreamRequest(m.top.streamParameters.assetKey, m.top.streamParameters.networkCode, m.top.streamParameters.apiKey)
' Set the player object so that the request can trigger the player's
' callbacks at stream initialization or playback events.
request.player = m.player
' Set the video node for the IMA DAI SDK to create ad UI as its child nodes.
request.adUiNode = m.top.video
requestResult = m.ima.requestStream(request)
if requestResult <> invalid
print "Error requesting stream ";requestResult
return
end if
m.streamManager = invalid
while m.streamManager = invalid
sleep(50)
m.streamManager = m.ima.getStreamManager()
end while
if m.streamManager = invalid
errors = CreateObject("roArray", 1, True)
invalidStreamManagerError = "Invalid stream manager"
print invalidStreamManagerError
errors.push(invalidStreamManagerError)
m.top.errors = errors
return
end if
if m.streamManager["type"] <> invalid and m.streamManager["type"] = "error"
errors = CreateObject("roArray", 1, True)
print "Stream request returns an error. " ; m.streamManager["info"]
errors.push(m.streamManager["info"])
m.top.errors = errors
return
end if
setupStreamManager()
m.streamManager.start()
end sub
הצגת Pod של שידורים ב-VOD
באובייקט m.testPodServingStream
, מאחסנים את קוד הרשת שבו נעשה שימוש
הבקשה של מקור הנתונים, כדי שמערכת Google Ad Manager תוכל לספק מזהה של מקור נתונים. גם לאחסן
כתובת ה-URL של המניפסט שמשמשת לגישה למניפסט הספציפי למשתמש במניפסט
שרת שינוי ועיבוד.
כדי לתמוך ב-AdUI, למשל עם הסמלים של בחירת המודעות, עליכם להעביר גם הפניה אל צומת שמכיל את סרטון התוכן שלך כחלק מהבקשה.
MainScene.xml
sub init()
m.video = m.top.findNode("myVideo")
m.video.notificationinterval = 1
m.testPodServingStream = {
title: "Pod Serving VOD Stream",
networkCode: "your-network-code",
VTPManifest: "https://.../manifest.m3u8?gam-stream-id=[[STREAMID]]",
subtitleConfig: []
}
runIMASDKTask()
end sub
sub runIMASDKTask()
m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
m.IMASDKTask.streamParameters = m.testPodservingStream
m.IMASDKTask.videoNode = m.video
m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
m.IMASDKTask.control = "RUN"
end sub
Sdk.xml
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
setupPlayerCallbacks()
loadAdPodStream()
end sub
sub loadAdPodStream()
request = m.ima.CreatePodVodStreamRequest(m.top.streamParameters.networkCode)
' Set the player object so that the request can trigger the player
' callbacks at stream initialization or playback events.
request.player = m.player
' Set the video node for the IMA DAI SDK to create ad UI as its child nodes.
request.adUiNode = m.top.video
requestResult = m.ima.requestStream(request)
if requestResult <> invalid
print "Error requesting stream ";requestResult
return
end if
m.streamManager = invalid
while m.streamManager = invalid
sleep(50)
m.streamManager = m.ima.getStreamManager()
end while
if m.streamManager = invalid
errors = CreateObject("roArray", 1, True)
invalidStreamManagerError = "Invalid stream manager"
print invalidStreamManagerError
errors.push(invalidStreamManagerError)
m.top.errors = errors
return
end if
if m.streamManager["type"] <> invalid and m.streamManager["type"] = "error"
errors = CreateObject("roArray", 1, True)
print "Stream request returns an error. " ; m.streamManager["info"]
errors.push(m.streamManager["info"])
m.top.errors = errors
return
end if
setupStreamManager()
m.streamManager.start()
end sub
הוספת פונקציות event listener והפעלת השידור
הצגת Pod של שידורים חיים
לאחר שליחת הבקשה לשידור, נשארו רק כמה דברים לעשות: להוסיף פונקציות event listener לעקוב אחר התקדמות המודעות ולהעביר הודעות Roku אל ה-SDK. חשוב להעביר את כל ההודעות ל-SDK כדי לוודא שהמודעה נכונה להפעלה. אם לא תעשו זאת, תקבלו דיווח בלתי הולם על צפיות במודעות.
בשלב הזה מוסיפים גם פונקציה שתחליף את פקודת המאקרו [[STREAMID]]
מזהה הסטרימינג, ומעבירים לנגן הווידאו את כתובת ה-URL המלאה של בקשת המניפסט.
ההטמעה הזו מקבלת את מזהה מקור הנתונים בשלב הזה, אבל בהתאם ל-VTP
יכול להיות שהוא יהיה זמין לפני השלב הזה.
MainScene.xml
function runIMASDKTask()
m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
m.IMASDKTask.streamParameters = m.testPodservingStream
m.IMASDKTask.videoNode = m.video
m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
m.sdkTask.observeField("adStitchedStreamInfo", "loadAdStitchedStream")
m.sdkTask.control = "RUN"
end function
sub loadAdStitchedStream(message as object)
print "Ad pod stream information ";message
adPodStreamInfo = message.getData()
manifest = m.testPodservingStream.manifest.Replace("[[STREAMID]]", adPodStreamInfo.streamId)
playStream(manifest, adPodStreamInfo.format)
end sub
sub playStream(url as string, format as string)
vidContent = createObject("RoSGNode", "ContentNode")
vidContent.url = url
vidContent.title = m.testPodservingStream.title
vidContent.streamformat = format
m.video.content = vidContent
m.video.setFocus(true)
m.video.visible = true
m.video.control = "play"
m.video.EnableCookies()
end sub
Sdk.xml
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
setupPlayerCallbacks()
loadAdPodStream()
if m.streamManager <> invalid
runLoop()
end if
end sub
sub runLoop()
m.top.videoNode.timedMetaDataSelectionKeys = ["*"]
' IMPORTANT: Failure to listen to the position and timedmetadata fields
' could result in ad impressions not being reported.
m.port = CreateObject("roMessagePort")
m.top.videoNode.observeField("position", m.port)
m.top.videoNode.observeField("timedMetaData", m.port)
m.top.videoNode.observeField("timedMetaData2", m.port)
m.top.videoNode.observeField("state", m.port)
while True
msg = wait(1000, m.port)
if m.top.videoNode = invalid
print "exiting"
exit while
end if
m.streamManager.onMessage(msg)
currentTime = m.top.videoNode.position
if currentTime > 3 And not m.top.adPlaying
m.top.videoNode.enableTrickPlay = true
end if
end while
end sub
sub setupStreamManager()
m.streamManager.addEventListener(m.sdk.AdEvent.ERROR, errorCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.START, startCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.FIRST_QUARTILE, firstQuartileCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.MIDPOINT, midpointCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.THIRD_QUARTILE, thirdQuartileCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.COMPLETE, completeCallback)
end sub
sub startCallback(ad as object)
print "Callback from SDK -- Start called - "
end sub
sub firstQuartileCallback(ad as object)
print "Callback from SDK -- First quartile called - "
end sub
sub midpointCallback(ad as object)
print "Callback from SDK -- Midpoint called - "
end sub
sub thirdQuartileCallback(ad as object)
print "Callback from SDK -- Third quartile called - "
end sub
sub completeCallback(ad as object)
print "Callback from SDK -- Complete called - "
end sub
function errorCallback(error as object)
print "Callback from SDK -- Error called - " ; error
m.errorState = True
end function
הצגת Pod של שידורים ב-VOD
לאחר שליחת הבקשה לשידור, נשארו רק כמה דברים לעשות: להוסיף פונקציות event listener לעקוב אחר התקדמות המודעות ולהעביר הודעות Roku אל ה-SDK. הוא חשוב להעביר את כל ההודעות אל ה-SDK כדי להבטיח שהמודעה נכונה להפעלה. אם לא תעשו זאת, תקבלו דיווח שגוי על צפיות במודעות.
MainScene.xml
sub runIMASDKTask()
m.IMASDKTask = createObject("roSGNode", "IMASDKTask")
m.IMASDKTask.streamParameters = m.testPodservingStream
m.IMASDKTask.videoNode = m.video
m.IMASDKTask.observeField("IMASDKInitialized", "handleIMASDKInitialized")
m.IMASDKTask.observeField("errors", "handleIMASDKErrors")
m.sdkTask.observeField("adStitchedStreamInfo", "loadAdStitchedStream")
m.sdkTask.control = "RUN"
end sub
sub loadAdStitchedStream(message as object)
print "Ad pod stream information ";message
adPodStreamInfo = message.getData()
end sub
sub playStream(url as string, format as string, subtitleConfig as object)
vidContent = createObject("RoSGNode", "ContentNode")
vidContent.title = m.testPodservingStream.title
vidContent.url = url
vidContent.subtitleConfig = subtitleConfig
vidContent.streamformat = format
m.video.content = vidContent
m.video.setFocus(true)
m.video.visible = true
m.video.control = "play"
m.video.EnableCookies()
end sub
Sdk.xml
sub runThread()
if not m.top.IMASDKInitialized
initializeIMASDK()
end if
setupPlayerCallbacks()
loadAdPodStream()
if m.streamManager <> invalid
runLoop()
end if
end sub
sub runLoop()
m.top.videoNode.timedMetaDataSelectionKeys = ["*"]
' IMPORTANT: Failure to listen to the position and timedmetadata fields
' could result in ad impressions not being reported.
m.port = CreateObject("roMessagePort")
m.top.videoNode.observeField("position", m.port)
m.top.videoNode.observeField("timedMetaData", m.port)
m.top.videoNode.observeField("timedMetaData2", m.port)
m.top.videoNode.observeField("state", m.port)
while True
msg = wait(1000, m.port)
if m.top.videoNode = invalid
exit while
end if
m.streamManager.onMessage(msg)
currentTime = m.top.videoNode.position
if currentTime > 3 and not m.top.adPlaying
m.top.videoNode.enableTrickPlay = true
end if
end while
end sub
sub setupStreamManager()
m.streamManager.addEventListener(m.sdk.AdEvent.ERROR, errorCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.START, startCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.FIRST_QUARTILE, firstQuartileCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.MIDPOINT, midpointCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.THIRD_QUARTILE, thirdQuartileCallback)
m.streamManager.addEventListener(m.sdk.AdEvent.COMPLETE, completeCallback)
end sub
sub startCallback(ad as object)
print "Callback from SDK -- Start called - "
end sub
sub firstQuartileCallback(ad as object)
print "Callback from SDK -- First quartile called - "
end sub
sub midpointCallback(ad as object)
print "Callback from SDK -- Midpoint called - "
end sub
sub thirdQuartileCallback(ad as object)
print "Callback from SDK -- Third quartile called - "
end sub
sub completeCallback(ad as object)
print "Callback from SDK -- Complete called - "
end sub
sub errorCallback(error as object)
print "Callback from SDK -- Error called - " ; error
m.errorState = True
end sub