2

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
    }
}

zaid afzal
  • 119
  • 1
  • 5

1 Answers1

0

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

Abdelrahman
  • 997
  • 2
  • 10
  • 24