A library for sending ad beacons from the client-side. Works with both traditional SSAI and HLS interstitials. Compatible with iOS/tvOS 15 and above.
Using Swift Package Manager, enter the URL of this package:
https://github.com/harmonicinc-com/client-side-ad-tracking-ios-lib
-
Import the library
import HarmonicClientSideAdTracking
-
Create an
AdBeaconingSession
object:let mySession = AdBeaconingSession()
-
Optionally, set the session's player to your own instance of AVPlayer:
let myAVPlayer = AVPlayer() mySession.player = myAVPlayer
-
Set the session's media URL to the master playlist of an HLS stream:
mySession.mediaUrl = "<hls-master-playlist-url>"
- Note that the
AdBeaconingSession
object will then do the following:- Try to obtain a manifest URL with a session ID (if the provided
mediaUrl
doesn't already contain one); - Try to obtain the corresponding metadata URL with the session ID.
- Try to obtain a manifest URL with a session ID (if the provided
- Note that the
-
Observe the session's
manifestUrl
by using the.onReceive(_:perform:)
method in SwiftUI (for UIKit, please see the example below). When it is set and not empty, create anAVPlayerItem
with the URL and set it in the player:if !manifestUrl.isEmpty { let myPlayerItem = AVPlayerItem(url: URL(string: manifestUrl)!) mySession.player.replaceCurrentItem(with: myPlayerItem) }
-
Create a
HarmonicAdTracker
object and initialize it with the session created above:let adTracker: HarmonicAdTracker? adTracker = HarmonicAdTracker(session: mySession)
-
Start the ad tracker:
adTracker?.start()
-
Start playing and beacons will be sent when ads are played:
mySession.player.play()
-
You may observe the following information from the session instance:
- To get the URLs with the session ID:
URLs available:
let sessionInfo = mySession.sessionInfo
sessionInfo.mediaUrl // String sessionInfo.manifestUrl // String sessionInfo.adTrackingMetadataUrl // String
- To get the list of
AdBreak
s returned from the ad metadata along with the status of the beaconing for each event.For example, in the firstlet adPods = mySession.adPods
AdBreak
ofadPods
:In the firstadPods[0].id // String adPods[0].startTime // Double: millisecondsSince1970 adPods[0].duration // Double: milliseconds adPods[0].ads // [Ad]
Ad
ofadPods[0].ads
:In the firstads[0].id // String ads[0].startTime // Double: millisecondsSince1970 ads[0].duration // Double: milliseconds ads[0].trackingEvents // [TrackingEvent]
TrackingEvent
ofads[0].trackingEvents
:trackingEvents[0].event // EventType trackingEvents[0].startTime // Double: millisecondsSince1970 trackingEvents[0].duration // Double: milliseconds trackingEvents[0].signalingUrls // [String] trackingEvents[0].reportingState // ReportingState
- To get the latest DataRange returned from the ad metadata.
To get the time in
let latestDataRange = mySession.latestDataRange
millisecondsSince1970
:latestDataRange.start // Double: millisecondsSince1970 latestDataRange.end // Double: millisecondsSince1970
- To get the status and information of the player.
Information available:
let playerObserver = mySession.playerObserver
playerObserver.currentDate // Date playerObserver.playhead // Double: millisecondsSince1970 playerObserver.primaryStatus // AVPlayer.TimeControlStatus playerObserver.hasInterstitialEvents // Bool playerObserver.interstitialStatus // AVPlayer.TimeControlStatus playerObserver.interstitialDate // Double: millisecondsSince1970 playerObserver.interstitialStoppedDate // Double: millisecondsSince1970 playerObserver.interstitialStartTime // Double: seconds playerObserver.interstitialStopTime // Double: seconds playerObserver.currentInterstitialDuration // Double: milliseconds
- To get the messages logged by the library.
For example, in the first
let logMessages = mySession.logMessages
LogMessage
:logMessages[0].timeStamp // Double: secondsSince1970 logMessages[0].message // String logMessages[0].isError // Bool
- To get the URLs with the session ID:
-
Stop the ad tracker when it is not needed:
adTracker?.stop()
In these examples, ad beacons will be sent while the stream is being played, but no UI is shown to indicate the progress of beaconing.
import SwiftUI
import AVKit
import HarmonicClientSideAdTracking
struct ContentView: View {
@StateObject private var mySession = AdBeaconingSession()
@State private var adTracker: HarmonicAdTracker?
var body: some View {
VideoPlayer(player: mySession.player)
.onAppear {
mySession.mediaUrl = "<hls-master-playlist-url>"
adTracker = HarmonicAdTracker(session: mySession)
}
.onReceive(mySession.sessionInfo.$manifestUrl) { manifestUrl in
if !manifestUrl.isEmpty {
let myPlayerItem = AVPlayerItem(url: URL(string: manifestUrl)!)
mySession.player.replaceCurrentItem(with: myPlayerItem)
mySession.player.play()
adTracker?.start()
}
}
.onDisappear {
adTracker?.stop()
}
}
}
import UIKit
import AVKit
import Combine
import HarmonicClientSideAdTracking
class ViewController: UIViewController {
private var mySession = AdBeaconingSession()
private var adTracker: HarmonicAdTracker?
private var sessionSub: AnyCancellable?
override func viewDidAppear(_ animated: Bool) {
mySession.mediaUrl = "<hls-master-playlist-url>"
adTracker = HarmonicAdTracker(session: mySession)
let controller = AVPlayerViewController()
controller.player = mySession.player
present(controller, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
sessionSub = mySession.$sessionInfo.sink { [weak self] sessionInfo in
guard let self = self else { return }
if !sessionInfo.manifestUrl.isEmpty {
let myPlayerItem = AVPlayerItem(url: URL(string: sessionInfo.manifestUrl)!)
mySession.player.replaceCurrentItem(with: myPlayerItem)
mySession.player.play()
adTracker?.start()
}
}
}
override func viewWillAppear(_ animated: Bool) {
adTracker?.stop()
}
}
The library consists of several SwiftUI views that are used in the demo project. They are used to show how to display the progress of beacon-sending, and are not required for the ad beaconing logic to work.
This view shows a list of AdBreakView
s.
-
Each
AdBreakView
indicates an ad break, and shows a list ofAdView
s, each representing an ad in this ad break. -
Each
AdView
indicates an ad, and shows a list ofTrackingEventView
s, each representing a tracking event in this ad. -
Each
TrackingEventView
indicates a tracking event, and shows information for this particular tracking event, including:- The event name
- The signaling URLs
- The time of the event
- The state of the beaconing of this event, which may be
idle
,connecting
,done
, orfailed
Shows information about playback:
- Playhead
- Time to next ad beack
- If interstitials are available:
- Last interstitial's event date
- Last interstitial's start time
- Last interstitial's end time
Also, the different URLs of the session:
- Media URL (set by the user)
- Manifest URL (the redirected URL with a session ID)
- Ad tracking metadata URL
Contains a VideoPlayer
with a debug overlay showing the real-world time and the latency. It also reloads by creating a new instance of player when the session's automaticallyPreservesTimeOffsetFromLive
option is changed.
A demo app (that can be run on both iOS and tvOS) on how this library (including the SwiftUI views) may be used is available at the following repository: https://github.com/harmonicinc-com/client-side-ad-tracking-ios