-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(iOS): rewrite DRM Module (#4136)
* minimal api * add suport for `getLicense` * update logic for obtaining `assetId` * add support for localSourceEncryptionKeyScheme * fix typo * fix pendingLicenses key bug * lint code * code clean * code clean * remove old files * fix tvOS build * fix errors loop * move `localSourceEncryptionKeyScheme` into drm params * add check for drm type * use DebugLog * lint * update docs * lint code * fix bad rebase * update docs * fix crashes on simulators * show error on simulator when using DRM * fix typos * code clean
- Loading branch information
1 parent
c96f7d4
commit 0e4c95d
Showing
15 changed files
with
576 additions
and
482 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
ios/Video/Features/DRMManager+AVContentKeySessionDelegate.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// | ||
// DRMManager+AVContentKeySessionDelegate.swift | ||
// react-native-video | ||
// | ||
// Created by Krzysztof Moch on 14/08/2024. | ||
// | ||
|
||
import AVFoundation | ||
|
||
extension DRMManager: AVContentKeySessionDelegate { | ||
func contentKeySession(_: AVContentKeySession, didProvide keyRequest: AVContentKeyRequest) { | ||
handleContentKeyRequest(keyRequest: keyRequest) | ||
} | ||
|
||
func contentKeySession(_: AVContentKeySession, didProvideRenewingContentKeyRequest keyRequest: AVContentKeyRequest) { | ||
handleContentKeyRequest(keyRequest: keyRequest) | ||
} | ||
|
||
func contentKeySession(_: AVContentKeySession, shouldRetry _: AVContentKeyRequest, reason retryReason: AVContentKeyRequest.RetryReason) -> Bool { | ||
let retryReasons: [AVContentKeyRequest.RetryReason] = [ | ||
.timedOut, | ||
.receivedResponseWithExpiredLease, | ||
.receivedObsoleteContentKey, | ||
] | ||
return retryReasons.contains(retryReason) | ||
} | ||
|
||
func contentKeySession(_: AVContentKeySession, didProvide keyRequest: AVPersistableContentKeyRequest) { | ||
Task { | ||
do { | ||
try await handlePersistableKeyRequest(keyRequest: keyRequest) | ||
} catch { | ||
handleError(error, for: keyRequest) | ||
} | ||
} | ||
} | ||
|
||
func contentKeySession(_: AVContentKeySession, contentKeyRequest _: AVContentKeyRequest, didFailWithError error: Error) { | ||
DebugLog(String(describing: error)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// | ||
// DRMManager+OnGetLicense.swift | ||
// react-native-video | ||
// | ||
// Created by Krzysztof Moch on 14/08/2024. | ||
// | ||
|
||
import AVFoundation | ||
|
||
extension DRMManager { | ||
func requestLicenseFromJS(spcData: Data, assetId: String, keyRequest: AVContentKeyRequest) async throws { | ||
guard let onGetLicense else { | ||
throw RCTVideoError.noDataFromLicenseRequest | ||
} | ||
|
||
guard let licenseServerUrl = drmParams?.licenseServer, !licenseServerUrl.isEmpty else { | ||
throw RCTVideoError.noLicenseServerURL | ||
} | ||
|
||
guard let loadedLicenseUrl = keyRequest.identifier as? String else { | ||
throw RCTVideoError.invalidContentId | ||
} | ||
|
||
pendingLicenses[loadedLicenseUrl] = keyRequest | ||
|
||
DispatchQueue.main.async { [weak self] in | ||
onGetLicense([ | ||
"licenseUrl": licenseServerUrl, | ||
"loadedLicenseUrl": loadedLicenseUrl, | ||
"contentId": assetId, | ||
"spcBase64": spcData.base64EncodedString(), | ||
"target": self?.reactTag as Any, | ||
]) | ||
} | ||
} | ||
|
||
func setJSLicenseResult(license: String, licenseUrl: String) { | ||
guard let keyContentRequest = pendingLicenses[licenseUrl] else { | ||
setJSLicenseError(error: "Loading request for licenseUrl \(licenseUrl) not found", licenseUrl: licenseUrl) | ||
return | ||
} | ||
|
||
guard let responseData = Data(base64Encoded: license) else { | ||
setJSLicenseError(error: "Invalid license data", licenseUrl: licenseUrl) | ||
return | ||
} | ||
|
||
do { | ||
try finishProcessingContentKeyRequest(keyRequest: keyContentRequest, license: responseData) | ||
pendingLicenses.removeValue(forKey: licenseUrl) | ||
} catch { | ||
handleError(error, for: keyContentRequest) | ||
} | ||
} | ||
|
||
func setJSLicenseError(error: String, licenseUrl: String) { | ||
let rctError = RCTVideoError.fromJSPart(error) | ||
|
||
DispatchQueue.main.async { [weak self] in | ||
self?.onVideoError?([ | ||
"error": RCTVideoErrorHandler.createError(from: rctError), | ||
"target": self?.reactTag as Any, | ||
]) | ||
} | ||
|
||
pendingLicenses.removeValue(forKey: licenseUrl) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// DRMManager+Persitable.swift | ||
// react-native-video | ||
// | ||
// Created by Krzysztof Moch on 19/08/2024. | ||
// | ||
|
||
import AVFoundation | ||
|
||
extension DRMManager { | ||
func handlePersistableKeyRequest(keyRequest: AVPersistableContentKeyRequest) async throws { | ||
if let localSourceEncryptionKeyScheme = drmParams?.localSourceEncryptionKeyScheme { | ||
try handleEmbeddedKey(keyRequest: keyRequest, scheme: localSourceEncryptionKeyScheme) | ||
} else { | ||
// Offline DRM is not supported yet - if you need it please check out the following issue: | ||
// https://github.com/TheWidlarzGroup/react-native-video/issues/3539 | ||
throw RCTVideoError.offlineDRMNotSupported | ||
} | ||
} | ||
|
||
private func handleEmbeddedKey(keyRequest: AVPersistableContentKeyRequest, scheme: String) throws { | ||
guard let uri = keyRequest.identifier as? String, | ||
let url = URL(string: uri) else { | ||
throw RCTVideoError.invalidContentId | ||
} | ||
|
||
guard let persistentKeyData = RCTVideoUtils.extractDataFromCustomSchemeUrl(from: url, scheme: scheme) else { | ||
throw RCTVideoError.embeddedKeyExtractionFailed | ||
} | ||
|
||
let persistentKey = try keyRequest.persistableContentKey(fromKeyVendorResponse: persistentKeyData) | ||
try finishProcessingContentKeyRequest(keyRequest: keyRequest, license: persistentKey) | ||
} | ||
} |
Oops, something went wrong.