WWDC18 — AVContentKeySession Best Practices

庭庭Play
BlendVision
Published in
3 min readAug 3, 2018

這篇是介紹 iOS FairPlay HLS Streaming 中, 如何優化 Content Key 驗證流程以及怎麼使用 AVContentKeySession 的 API

適合有接觸過 FairPlay HLS Streaming 的 iOS 開發者

AVContentKeySession可以解決哪些問題呢 ?

  1. 避免過多的Client (iOS device) 同時間問候 FPS Key Server (To reduce load on Key server)
  2. 獨立 Content Key 驗證流程於播放情境中 (decouple)
FairPlay Streaming Overview

在 AVContentKeySession 未出世前, 我們仰賴 AVAssetResourceLoaderDelegate 的觸發時間點來實作 Content Key的驗證.

舉個簡單情境是 :

  1. 使用者選了一部加密的影片
  2. 按下播放鍵, (透過AVPlayer : replaceCurrentItem, 觸發 AVURLAsset 設定的 AVAssetResourceLoaderDelegate )
  3. Client 準備 Secure Playback Context(SPC) 送往 FPS Key Server, Server 驗證完後傳遞Content Key Context(CKC response) 給 Client, Client 再傳給AVFoundation看結果如何.
  4. 完成 Content Key 驗證的任務

Session 507 最關鍵的一段就是:

AVContentKeySession, essentially, changes that model. It decouples key loading from media loading or playback and gives applications more control over the timing of key loading.

AVContentKeySession allows applications to initiate key loading on their own at any point in time. This opens up new use cases, allows applications to optimize key delivery, and improve different aspects of playback experience.

Playback startup is one such thing AVContentKeySession could help improve.

Instead of waiting for AVFoundation to send on demand key loading requests.

也就是AVContentKeySession可以在播放前, 就先進行Content Key 驗證動作.可以避開像是熱門播放時段時, 巨量數目的Client要求FPS Key Server 驗證, 容易造成負載過重, 進而當機.

舉例來說 : 未來有個 Live 事件即將在 2020 / 07 / 24 15:00, 是東京奧運開幕表演, 當大量使用者在這個時機點開啟播放器, 就很容易造成負擔, 而透過這個AVContentKeySession, 我們可以在開啟播放器之前就做好 Content Key驗證的動作. 像是使用者打開App 在歡迎頁面或者是影片介紹頁面驗證拿等等.

AVContentKeySession 要怎麼使用呢 ?

大致分為四個步驟
1. Prepare AVURLAsset and Key Identifier

let urlAsset = AVURLAsset(url: URL(string: “https://helloKitty.m3u8”)!)let keyIdentifier = “skd://52d042fa8ed41f7f3d1f5721cc192022+52d042fa8ed41f7f3d1f5721cc192022”

2. Set AVContentKeySessionDelegate to AVContentKeySession

let contentKeySession = AVContentKeySession(keySystem: .fairPlayStreaming)
let contentKeyDelegate = ContentKeyDelegate()
contentKeySession.setDelegate(contentKeyDelegate, queue: contentKeyDelegateQueue)
class ContentKeyDelegate: NSObject, AVContentKeySessionDelegate {
func contentKeySession(_ session: AVContentKeySession, didProvide keyRequest: AVContentKeyRequest) {
// handle keyRequest
}
}

3. Start key loading process by AVContentKeySession APIs

contentKeySession.addContentKeyRecipient(urlAsset)
contentKeySession.processContentKeyRequest(withIdentifier: keyIdentifier, initializationData: nil, options: nil)

4. Handle key loading process in AVContentKeySessionDelegate function

func contentKeySession(_ session: AVContentKeySession, didProvide keyRequest: AVContentKeyRequest) {    let completionHandler = { [weak self] (spcData: Data?, error: Error?) in    let ckcResponseData = sendSpcDataToKeyModuleServer(spcData)
let keyResponse = AVContentKeyResponse(fairPlayStreamingKeyResponseData: ckcResponseData!)
keyRequest.processContentKeyResponse(keyResponse)
} keyRequest.makeStreamingContentKeyRequestData(
forApp: applicationCertificate,
contentIdentifier: assetIDData,
options: [AVContentKeyRequestProtocolVersionsKey: [1]],
completionHandler: completionHandler
)
}

完成四個步驟後, 就可以把 urlAsset 傳遞到 AVPlayer 做播放的動作, 詳細的內容可以觀看 KKStream WWDC Report 影片(8:30 ~ 15:00), 而重要的Sample codes 是從 https://developer.apple.com/streaming/fps/ Apple 網站下載下來的

Download Link (but it needs permission)
Here ! ! !

而在影片KKStream WWDC Report 27:00 ~ 30:00 左右有展現這個Sample codes 應該要修改的地方, 可以參考一下

Master Playlist 包含 Key Identifier

另外建議把 Key Identifier (ex: skd://xxxxx) 放在Master Playlist, 不用像以往在 Media Playlist(又稱為Variant Playlist) 才認得 Key Identifier 進而去做 Content Key 驗證. (不過現階段KKStream 還沒引入這個方式, 已列為將來的Action Item)
根據Preliminary-Spec.pdf 以及WWDC16:Advances in AVFoundation Playback 都有提及此建議

Preload keys in Master Playlist
// 設定此flag為true
urlAsset.resourceLoader.preloadsEligibleContentKeys = true
urlAsset.resourceLoader.setDelegate(self, queue: DispatchQueue(label: "com.kkstream.tw"))
// 會立即觸發 AVAssetResourceLoaderDelegate 的
// public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest)

Session 504 核心的概念大致上到這裡結束, Offline Rental 與 Error report log 在影片中也是簡單帶過, 改天有空再更深入研究嚕~

Reference

  1. WWDC18: AVContentKeySession Best Practices
  2. WWDC16: Advances in AVFoundation Playback
  3. KKStream WWDC Report
  4. Preliminary-Spec.pdf

--

--