This is below my response getting from backend apis.
How can i play videos with .mpd extension in swift AVPlayer with widevine and no widevine.
My certificate data is now downloading , but I'm unable to get streamingContentKeyRequestData.
I'm following this medium article.
https://medium.com/@burak.oguz/ios-fairplay-drm-integration-with-different-use-cases-8aff3d4248dd
Response JSON :
{
"url": "https://z2cltd.akamaized.net/example-4671-mp4-cbcs.mpd",
"fairPlayCertificateUrl": "https://mw.example.net/static/FairPlay.der",
"drms": {
"com.widevine.alpha": "https://mw.example.net/widevine_proxy",
"com.apple.fps": "https://mw.example.net/ksm",
"com.apple.fps.1_0": "https://mw.example.net/ksm"
},
}
ViewController :
class ViewController: UIViewController {
var player: AVPlayer?
var asset: AVURLAsset?
override func viewDidLoad() {
super.viewDidLoad()
// Create the AVURLAsset and assign the delegate
guard let url = URL(string: "htps://z2cltd.akamaized.net/mini01/vods/49/s1e1-andhera-ujala-ghani-chaon-copy-3395/64366c9ccc181-4606-mp4-cbcs.mpd") else {
return
}
asset = AVURLAsset(url: url)
asset?.resourceLoader.setDelegate(self, queue: DispatchQueue.global(qos: .default))
// Create an AVPlayerItem using the AVURLAsset
let playerItem = AVPlayerItem(asset: asset!)
//
// Create an AVPlayer using the AVPlayerItem
player = AVPlayer(playerItem: playerItem)
// Add the AVPlayerLayer to the mediaView
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = view.bounds
playerLayer.videoGravity = .resizeAspectFill
playerLayer.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions(), context: nil)
view.layer.addSublayer(playerLayer)
// Play the content using the AVPlayer
player?.play()
}
private func observePlayerItemProperties(for item: AVPlayerItem) {
item.observe(\.status, changeHandler: self.onStatusObserverChanged)
print(item.observe(\.status, changeHandler: self.onStatusObserverChanged))
}
private func onStatusObserverChanged(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<AVPlayerItem.Status>) {
guard playerItem.status != .failed else {
if let error = playerItem.error as? Error {
// DRM Errors handled here
print("DRM errors:\(error)")
}
return
}
}
let keyServerUrl: URL = URL(string: "https://mw.hivesys.net/")!
}
extension ViewController: AVAssetResourceLoaderDelegate {
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
let url = URL(string: "https://z2cltd.akamaized.net/mini01/vods/49/s1e1-andhera-ujala-ghani-chaon-copy-3395/64366c9ccc181-4606-mp4-cbcs.mpd")
// Get the content id. Content id will be stored in the host of the request url
guard let contentId = url!.host, let contentIdData = contentId.data(using: String.Encoding.utf8) else {
print("Unable to read the content id.")
// loadingRequest.finishLoading(with: DRMError.noContentIdFound)
return false
}
// Request SPC data from OS
var _spcData: Data?
var certificateDataNeed: Data?
// var _spcError: Error?
let certificateUrl = URL(string: "https://mw.hivesys.net/static/FairPlay.der")!
let certificateDataTask = URLSession.shared.dataTask(with: certificateUrl) { (data, response, error) in
if let certificateData = data {
// let contentIdHeaderValue = "spc=\(contentIdBase64String ?? ""), cert=\(certificateData.base64EncodedString(options: []))"
certificateDataNeed = certificateData
// Use the obtained certificateData and contentIdHeaderValue as needed
// Handle the provided content key request and provide the necessary response
// This involves retrieving the license from the license server and providing it to the key request
print("Data :\(certificateData)")
// print("contentIdHeaderValue :\(contentIdHeaderValue)")
do {
// **This is where I'm getting stucked unable to get spcData**
_spcData = try loadingRequest.streamingContentKeyRequestData(forApp: certificateData, contentIdentifier: contentIdData, options: [AVAssetResourceLoadingRequestStreamingContentKeyRequestRequiresPersistentKey: true as AnyObject])
guard let spcData = _spcData, let dataRequest = loadingRequest.dataRequest else {
// loadingRequest.finishLoading(with: DRMError.noSPCFound(underlyingError: _spcError))
print("Unable to read the SPC data.")
return()
}
let stringBody: String = "spc=\(spcData.base64EncodedString())&assetId=\(contentId)"
var ckcRequest = URLRequest(url: self.keyServerUrl)
ckcRequest.httpMethod = "POST"
ckcRequest.httpBody = stringBody.data(using: String.Encoding.utf8)
URLSession(configuration: URLSessionConfiguration.default).dataTask(with: ckcRequest) { data, _, error in
guard let data = data else {
print("Error in response data in CKC request: \(error)")
// loadingRequest.finishLoading(with: DRMError.unableToFetchKey(underlyingError: _spcError))
return
}
// The CKC is correctly returned and is now send to the `AVPlayer` instance so we
// can continue to play the stream.
guard let ckcData = Data(base64Encoded: data) else {
print("Can't create base64 encoded data")
//loadingRequest.finishLoading(with: DRMError.cannotEncodeCKCData)
return
}
// If we need non-persistent token, then complete loading
// dataRequest.respond(with: data)
// loadingRequest.finishLoading()
// If we need persistent token, then it is time to add persistence option
var persistentKeyData: Data?
do {
persistentKeyData = try loadingRequest.persistentContentKey(fromKeyVendorResponse: ckcData, options: nil)
} catch {
print("Failed to get persistent key with error: \(error)")
// loadingRequest.finishLoading(with: DRMError.unableToGeneratePersistentKey))
return
}
// set type of the key
loadingRequest.contentInformationRequest?.contentType = AVStreamingKeyDeliveryPersistentContentKeyType
dataRequest.respond(with: persistentKeyData!)
loadingRequest.finishLoading()
}.resume()
} catch let error {
// _spcError = error
print("Failed to get stream content key with error: \(error)")
}
}
}
certificateDataTask.resume()
return true
}
}
AVPlayer does not support DASH (.mpd) nor WideVine. AVPlayer Supports HLS streams, and supports only Apple FairPlay DRM System for protected Streams.
Refer to Apple specification documentation for Apple devices.
https://developer.apple.com/documentation/http-live-streaming/hls-authoring-specification-for-apple-devices