Skip to content

Instantly share code, notes, and snippets.

@samueleastdev
Forked from neha-bansal790/DRMFairplay.swift
Created August 31, 2021 18:11
Show Gist options
  • Save samueleastdev/26b8700b4508ae6d703ce65fa9cc5328 to your computer and use it in GitHub Desktop.
Save samueleastdev/26b8700b4508ae6d703ce65fa9cc5328 to your computer and use it in GitHub Desktop.
DRM fairplay with hls integration
//
// DRMFairplay.swift
// Collection
//
// Created by B0203948 on 04/02/20.
// Copyright © 2020 wynk. All rights reserved.
//
import UIKit
import AVFoundation
class DRMFairplay: AVPlayer {
private let queue = DispatchQueue(label: "com.icapps.fairplay.queue")
func play(asset: AVURLAsset) {
// Set the resource loader delegate to this class. The `resourceLoader`'s delegate will be
// triggered when FairPlay handling is required.
asset.resourceLoader.setDelegate(self as? AVAssetResourceLoaderDelegate, queue: queue)
// Load the asset in the player.
let item = AVPlayerItem(asset: asset)
// Set the current item in this player instance.
replaceCurrentItem(with: item)
// Start playing the item. From the moment the `play` is triggered the `resourceLoader` will
// do the rest of the work.
play()
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
// We first check if a url is set in the manifest.
guard loadingRequest.request.url != nil else {
print("failed...", #function, "Unable to read the url/host data.")
loadingRequest.finishLoading(with: NSError(domain: "com.domain.error", code: -1, userInfo: nil))
return false
}
// When the url is correctly found we try to load the certificate date. Watch out! For this
// example the certificate resides inside the bundle. But it should be preferably fetched from
// the server.
guard
let certificateURL = Bundle.main.url(forResource: "certificate", withExtension: "der"),
let certificateData = try? Data(contentsOf: certificateURL) else {
print("failed...", #function, "Unable to read the certificate data.")
loadingRequest.finishLoading(with: NSError(domain: "com.domain.error", code: -2, userInfo: nil))
return false
}
// Request the Server Playback Context.
let contentId = "somehls_1234"
guard
let contentIdData = contentId.data(using: String.Encoding.utf8),
let spcData = try? loadingRequest.streamingContentKeyRequestData(forApp: certificateData, contentIdentifier: contentIdData, options: nil),
let dataRequest = loadingRequest.dataRequest else {
loadingRequest.finishLoading(with: NSError(domain: "com.domain.error", code: -3, userInfo: nil))
print("failed...", #function, "Unable to read the SPC data.")
return false
}
// Request the Content Key Context from the Key Server Module.
let ckcURL = URL(string: "https://www.abc.com/ckc")!
var request = URLRequest(url: ckcURL)
request.httpMethod = "POST"
request.httpBody = spcData
let session = URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: request) { data, response, error in
if let data = data {
// The CKC is correctly returned and is now send to the `AVPlayer` instance so we
// can continue to play the stream.
dataRequest.respond(with: data)
loadingRequest.finishLoading()
} else {
print("failed....", #function, "Unable to fetch the CKC.")
loadingRequest.finishLoading(with: NSError(domain: "com.domain.error", code: -4, userInfo: nil))
}
}
task.resume()
return true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment