ערכות IMA SDK מאפשרות לכם לשלב בקלות מודעות מולטימדיה באתרים ובאפליקציות שלכם. ערכות IMA SDK יכולות לשלוח בקשה להצגת מודעות מכל שרת מודעות שתואם ל-VAST, ולנהל את הפעלת המודעות באפליקציות שלך. בעזרת ערכות IMA DAI SDK, אפליקציות שולחות בקשה לשידור וידאו של מודעה ותוכן – VOD או תוכן בשידור חי. לאחר מכן, ה-SDK יחזיר שידור וידאו משולב, כך שלא יהיה צורך לנהל את המעבר בין מודעות וידאו בתוכן לבין מודעות וידאו בתוך האפליקציה.
איך בוחרים את פתרון DAI שמעניין אתכם
במדריך הזה מוסבר איך להפעיל שידור חי או שידור VOD ב-DAI Pod באמצעות IMA DAI SDK ל-Roku.
סקירה כללית בנושא הצגת מודעות Pod של 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 של סטרימינג.
הצגת Pod של שידורים חיים
בשידורים חיים, נגן הסטרימינג הזה משתמש בשלוש שיטות לקריאה חוזרת: 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
. בקריאה החוזרת (callback) של streamInitialized
, חשוב להקפיד להתקשר ל-StreamManager.loadThirdPartyStream()
. אחרת, ערכת ה-SDK לא תפעיל את הפונקציה loadUrl
.
בשלב הזה, תבקשו גם מהשותף לטכנולוגיית הווידאו (VTP) את כתובת ה-URL של השידור עם מזהה השידור שקיבלתם ב-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 Ad Manager צריך כדי לזהות את מקור הנתונים הרלוונטי, כמו קוד רשת ומפתח נכס מותאם אישית. צריך גם לאחסן את כתובת ה-URL של המניפסט שמשמשת לגישה לשרת המניפולציה של המניפסט. במקרה כזה, צריך להוסיף את מזהה מקור הנתונים של Google לכתובת ה-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 של שידורים חיים
אחרי שמבקשים להפעיל את השידור, נשארו רק כמה דברים לעשות: להוסיף מאזינים לאירועים כדי לעקוב אחרי ההתקדמות של המודעות ולהעביר הודעות מ-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
אחרי שמבקשים להפעיל את השידור, נשארו רק כמה דברים לעשות: להוסיף מאזינים לאירועים כדי לעקוב אחרי ההתקדמות של המודעות ולהעביר הודעות מ-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