Dependencies:
- Streamroot SDK 3.13.0
- Google IMA DAI SDK for iOS v3.9.3
The full integration can be found in the DNA Sample repo
Google Dynamic Ad Insertion
Google DAI is a Server Side Ad Insertion (SSAI) provider that enable ad insertion in Live and VoD stream. You can learn more about it here.
In order to request and track ads, Google provide a SDK that will be integrated alongside AVPlayer. Please refer to the official Google documentation to learn how to integrate it.
In this article, we will guide you to properly integrate Streamroot DNA SDK with the Google IMA SDK and AVPlayer.
Project setup
Installation
CocoaPods
Cocoapods 1.6.0 + is recommended
To integrate StreamrootSDK into your Xcode project using CocoaPods, specify this in your Podfile
:
use_frameworks!
target ' <Your Target Name >'
pod 'StreamrootSDK', '~> 3.13.0'
pod 'GoogleAds-IMA-iOS-SDK '
end
Then, run the following command:
$ pod update
Finally, open the generated Workspace.
Custom IMAAVPlayerVideoDisplay
In order to use Google DAI with the CDN Mesh Delivery SDK, IMAAVplayerVIdeoDisplay
has to be overridden in order to get the manifest URL and activate the Mesh Delivery.
Here is the original integration of the IMAAVplayerVIdeoDisplay
: https://developers.google.com/interactive-media-ads/docs/sdks/ios/dai/quickstart
class DNAAVPlayerVideoDisplay: IMAAVPlayerVideoDisplay {
private(set) var dnaClient: DNAClient?
private(set) var dnaConfig: DNAConfiguration
private var strKey: String {
return self.dnaConfig.streamrootKey
}
private var latency: Int {
return self.dnaConfig.latency
}
init!(avPlayer player: AVPlayer!, dnaConfig config: DNAConfiguration) {
self.dnaConfig = config
super.init(avPlayer: player)
}
override func loadStream(_ streamURL: URL!, withSubtitles subtitles: [Any]!) {
print(" Intercepted url \(String(describing: streamURL))")
var fetchedUrl: URL!
do {
fetchedUrl = try startStreamURL(streamURL)
} catch let error {
print("\(error)")
fetchedUrl = streamURL
}
super.loadStream(fetchedUrl, withSubtitles: subtitles)
}
deinit {
dnaClient?.stop()
}
}
Implement DNAClientDelegate
extension DNAAVPlayerVideoDisplay: DNAClientDelegate {
func playbackTime() -> Double {
if let player = self.player {
return CMTimeGetSeconds(player.currentTime())
}
return 0
}
public func loadedTimeRanges() -> [NSValue] {
guard let player = self.player else {
return []
}
guard let playerItem = player.currentItem else {
return []
}
let timeRanges = playerItem.loadedTimeRanges
return timeRanges.map { (value) -> NSValue in
NSValue(timeRange: TimeRange(range: value.timeRangeValue))
}
}
func updatePeakBitRate(_ bitRate: Double) {
player?.currentItem?.preferredPeakBitRate = bitRate
}
public func bufferTarget() -> Double {
if #available(iOS 10.0, tvOS 10.0, *) {
return self.player?.currentItem?.preferredForwardBufferDuration ?? 0
}
return 0.0
}
public func setBufferTarget(_ target: Double) {
if #available(iOS 10.0, tvOS 10.0, *) {
self.player?.currentItem?.preferredForwardBufferDuration = target
}
}
}
An Intermediary struct can be created to gather all CDN Mesh Delivery options:
struct DNAConfiguration {
let streamrootKey: String
let contentId: String?
let latency: Int
let property: String?
let backendHost: URL?
init(streamrootKey: String,
contentId: String? = nil,
latency: Int = 0,
property: String? = nil,
backendHost: URL? = nil) {
self.streamrootKey = streamrootKey
self.contentId = contentId
self.latency = latency
self.property = property
self.backendHost = backendHost
}
}
And the configuration can be used as following to instantiate a DNAClient
extension DNAAVPlayerVideoDisplay {
func startStreamURL(_ url: URL) throws -> URL? {
var builder = DNAClient.builder().dnaClientDelegate(self)
builder = builder.streamrootKey(strKey)
if self.latency > 0 {
builder = builder.latency(self.latency)
}
if let backendHost = dnaConfig.backendHost {
builder = builder.backendHost(backendHost)
}
if let contentId = dnaConfig.contentId, !contentId.isEmpty {
builder = try builder.contentId(contentId)
}
if let property = dnaConfig.property, !property.isEmpty {
builder = builder.property(property)
}
self.dnaClient = try builder.start(url)
guard let localUrlString = dnaClient?.manifestLocalURLPath else {
return url
}
guard let localUrl = URL(string: localUrlString) else {
return url
}
return localUrl
}
}