IMA SDK מאפשר לכם לשלב בקלות מודעות מולטימדיה באתרים ובאפליקציות שלכם. IMA SDK יכול לשלוח בקשה להצגת מודעות מכל שרת מודעות שתואם ל-VAST ולנהל את ההפעלה של המודעות באפליקציות שלך. בעזרת ערכות IMA DAI SDK, אפליקציות שולחות בקשות לשידור וידאו של מודעה או תוכן וידאו - VOD או תוכן בשידור חי. לאחר מכן, ה-SDK יחזיר שידור וידאו משולב, כך שלא יהיה צורך לנהל את המעבר בין מודעות וידאו לתוכן בתוך האפליקציה.
בחירת פתרון DAI שמעניין אתכם
מדריך זה מדגים איך להפעיל שידור חי או שידור VOD של DAI Pod באמצעות IMA DAI SDK ל-Roku.
סקירה כללית של הצגת IMA DAI Pod
כדי להטמיע הצגה של רצף מודעות באמצעות IMA DAI, יש שני רכיבי SDK עיקריים, שמפורטים במדריך הזה:
StreamRequest.createPodLiveStreamRequest()
/StreamRequest.createPodVodStreamRequest()
: יצירת אובייקט שמגדיר בקשה לשידור לשרתי הפרסום של Google. הבקשות האלה מציינות קוד רשת, ו-Pod Liveima.StreamRequest
מחייב גם מפתח נכס מותאם אישית ומפתח API אופציונלי.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 DAI SDK הוא טעינה והפעלה של 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.
הצגת רצף מודעות בשידור חי
בשידורים חיים, נגן השידורים הזה מטמיע שלוש שיטות קריאה חוזרת: streamInitialized
, adBreakStarted
ו-adBreakEnded
.
להשבית גם הפעלת טריקים בזמן טעינת השידור. כך המשתמשים לא יוכלו לדלג על מודעה לפני סרטון (pre-roll) ברגע שהיא מתחילה, לפני ההפעלה של האירוע של ההפסקה למודעות.
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>
הצגת רצף מודעות ב-VOD
בשידורי VOD, נגן השידור הזה משתמש ב-4 שיטות של קריאה חוזרת (callback):
streamInitialized
, loadUrl
, adBreakStarted
ו-adBreakEnded
. בקריאה החוזרת של streamInitialized
, חשוב להקפיד להתקשר אל StreamManager.loadThirdPartyStream()
. אם לא תעשו זאת, ה-SDK לא יפעיל את הפונקציה loadUrl
.
בשלב הזה תוכלו גם לבקש כתובת URL של השידור משותף טכנולוגיית הווידאו (VTP) עם מזהה שידור שהתקבל ב-loadAdPodStream()
. לאחר מכן, מפעילים את הפקודה StreamManager.loadThirdPartyStream()
באמצעות המניפסט של רצף המודעות וכל הכתוביות שמוחזרות מה-VTP.
להשבית גם הפעלת טריקים בזמן טעינת השידור. כך המשתמשים לא יוכלו לדלג על מודעה לפני סרטון (pre-roll) ברגע שהיא מתחילה, לפני ההפעלה של האירוע של ההפסקה למודעות.
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
אחרי שיש לכם נגן סטרימינג, תוכלו ליצור בקשת סטרימינג ולבצע אותה.
בדוגמה הזו יש נתונים של רצף להצגת רצף שמאוחסן ב-m.testPodServingStream
.
הצגת רצף מודעות בשידור חי
באובייקט m.testPodServingStream
, מאחסנים את הפרמטרים שנדרשים ל-Google Ad Manager כדי לזהות את מקור הנתונים המדובר, כמו קוד רשת ומפתח נכס מותאם אישית. צריך לאחסן גם את כתובת ה-URL של המניפסט שמשמשת לגישה לשרת המניפולציה של המניפסט. במקרה כזה, צריך להוסיף את מזהה Google Stream לכתובת ה-URL של המניפסט אחרי החזרת הבקשה של השידור.
כדי שתהיה לך אפשרות לתמוך ב-AdUI, כמו הסמלים של adChoices, עליך להעביר כחלק מהבקשה הפניה לצומת שמכיל את סרטון התוכן שלך.
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
הצגת רצף מודעות ב-VOD
באובייקט m.testPodServingStream
עליכם לאחסן את קוד הרשת שנעשה בו שימוש בבקשת השידור, כדי ש-Google Ad Manager יוכל לספק מזהה מקור נתונים. בנוסף, צריך לאחסן את כתובת ה-URL של המניפסט שמשמשת לגישה למניפסט הספציפי למשתמש בשרת המניפולציה של המניפסט.
כדי שתהיה לך אפשרות לתמוך ב-AdUI, כמו הסמלים של adChoices, עליך להעביר כחלק מהבקשה הפניה לצומת שמכיל את סרטון התוכן שלך.
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 ולהתחיל את השידור
הצגת רצף מודעות בשידור חי
לאחר שליחת הבקשה לשידור, נשארו לכם רק כמה דברים לעשות: להוסיף פונקציות 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
הצגת רצף מודעות ב-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