# Apple FairPlay

Note

ฟีเจอร์ DRM ของ ByteArk Player รองรับเฉพาะผู้ใช้ ByteArk Video Cloud for Business หากคุณต้องการใช้งานกรุณาติดต่อ sales@byteark.com

ByteArk Player SDK for iOS รองรับ Apple FairPlay Streaming (FPS) (opens new window) สำหรับการเล่นวิดีโอที่ป้องกันด้วย DRM ในการเปิดใช้งานฟีเจอร์นี้ คุณต้อง implement protocol ByteArkPlayerDrmDataSource เมื่อ SDK ตรวจพบเนื้อหาที่เข้ารหัสด้วย FairPlay จะร้องขอข้อมูลและ Key ที่จำเป็นสำหรับการถอดรหัสจากแอปของคุณ

Note

FairPlay ต้องใช้ source ในรูปแบบ HLS (.m3u8)

ข้อควรระวัง

FairPlay decryption ทำงานได้บนอุปกรณ์จริงเท่านั้น ไม่สามารถใช้งานบน Simulator ได้

ByteArkPlayerDrmDataSource Protocol

// A dataSource requests the necessary data to decrypt Apple FairPlay Drm content
@objc public protocol ByteArkPlayerDrmDataSource: AnyObject {
    /// Called when player needs to decrypt the current protected content and requires a content identifier (content id)  from the application to start the decryption process
    ///
    /// - Parameters:
    ///     - url: The url of the resource being loaded.
    ///     - completionHandler: The handler block used to provide the content identifier to the ByteArk Player.
    ///
    func contentIdentifier(for url: URL, completionHandler handler: @escaping (_ contentIdentifier: Data?) -> Void)
    /// Called when player needs to decrypt the current protected content and requires an application certificate from the application to start the decryption process
    ///
    /// - Parameters:
    ///     - url: The url of the resource being loaded.
    ///     - completionHandler: The handler block used to provide the application certificate to the ByteArk Player, the Application Certificate data you receive after registering an FPS playback app.
    ///
    func applicationCertificate(for url: URL, completionHandler handler: @escaping (_ certificate: Data?) -> Void)
    /// Called when player  needs to decrypt the current protected content and requires a content key from the application to start the decryption process
    ///
    /// - Parameters:
    ///     - spcData: The SPC (Server Playback Context) message from the operating system which must be sent to the Key Server in order to obtain the CKC (Content Key Context) message.
    ///     - completionHandler: The completion block used to provide CKC (Content Key Context) that received from  the Server Response to the ByteArk Player.
    ///
    func contentKey(with spcData: Data, completionHandler handler: @escaping (_ ckcData: Data?) -> Void)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# การใช้งาน

  1. Implement method contentIdentifier(for url: URL, completionHandler:) ใน class ของคุณ method นี้ใช้ขอ identifier ของเนื้อหาที่ได้รับการป้องกัน แล้วส่งกลับผ่าน completion block
func contentIdentifier(for url: URL, completionHandler handler: @escaping (Data?) -> Void) {
    // extract content identifier from url
    if #available(iOS 16.0, *) {
        handler(url.host()?.data(using: .utf8))
    } else {
        // Fallback on earlier versions
        handler(url.host?.data(using: .utf8))
    }
}
1
2
3
4
5
6
7
8
9
  1. Implement method applicationCertificate(for url: URL, completionHandler:) method นี้ใช้ขอ Application Certificate ซึ่งต้องส่งกลับผ่าน completion block
func applicationCertificate(for url: URL, completionHandler handler: @escaping (Data?) -> Void) {
    // request an application certificate from server
    var request = URLRequest(url: URL(string: "APPLICATION_CERTIFICATE_URL")!)
    request.httpMethod = "GET"
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        handler(data)
    }
    task.resume()
}
1
2
3
4
5
6
7
8
9
10
11
  1. Implement method contentKey(with spcData: Data, completionHandler:) method นี้จะได้รับข้อมูล SPC (Server Playback Context) ซึ่งต้องส่งไปยัง Key Server เพื่อขอ CKC (Content Key Context) แล้วส่ง CKC กลับผ่าน completion block
func contentKey(with spcData: Data, completionHandler handler: @escaping (Data?) -> Void) {
    var request = URLRequest(url: URL(string: "APPLE_FAIRPLAY_KEY_SERVER_URL")!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    // convert spc to base64 and set json body
    let json: [String: Any] = [ "spc": spcData.base64EncodedString() ]
    let jsonData = try? JSONSerialization.data(withJSONObject: json)
    request.httpBody = jsonData
    let task = URLSession.shared.dataTask(with: request) {  (data, response, error) in
        guard let data = data,
              let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
              let ckcString = json["ckc"] as? String,
              let ckcData = Data(base64Encoded: ckcString)
        else {
            handler(nil)
            return
        }
        handler(ckcData)
    }
    task.resume()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  1. กำหนด ByteArkPlayerDrmDataSource ที่คุณ implement ให้กับ ByteArkPlayerItemBuilder
do {
    let item =  try ByteArkPlayerItemBuilder()
        .title("FairPlay Source")
        .media(URL(string: "<HLS_M3U8_URL>")!)
        .drmDataSource(YOUR_DRM_DATA_SOURCE_IMPLEMENTATION)
        .build()
    let config = try ByteArkPlayerConfigBuilder()
        .autoplay(true)
        .item(item)
        .build()
    bytearkPlayerViewController.player.configure(with: config)
} catch {
    print(error.localizedDescription)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# ส่ง Custom Header ไปยัง License Server

หาก License server ต้องการ Authorization header หรือ header อื่นๆ สามารถกำหนดใน license request ภายใน contentKey(with:completionHandler:)

func contentKey(with spcData: Data, completionHandler handler: @escaping (Data?) -> Void) {
    var request = URLRequest(url: URL(string: "APPLE_FAIRPLAY_KEY_SERVER_URL")!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("Bearer <YOUR_TOKEN>", forHTTPHeaderField: "Authorization")
    // ...
}
1
2
3
4
5
6
7
8

Note

หากใช้งาน ByteArk Multi-DRM สามารถดูวิธีสร้าง JWT Token สำหรับ Authorization header ได้ที่ ขั้นตอนการสร้าง Authorization Token สำหรับใช้งาน DRM License Server