Thanks, the whole translation from this:
func requestApplicationCertificate() throws -> Data {
print("requestApplicationCertificate called")
// MARK: ADAPT - You must implement this method to retrieve your FPS application certificate.
var certificateData: Data? = nil
let request = NSMutableURLRequest(url: URL(string: DNSRestServices.DNS_FAIRLPLAY_SERVER_URL)!)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.dataTask(with: request as URLRequest) { (responseData, _, error) -> Void in
certificateData = responseData
semaphore.signal()
}.resume()
semaphore.wait(timeout: .distantFuture)
guard certificateData != nil else {
throw ProgramError.missingApplicationCertificate
}
return certificateData!
}
func requestContentKeyFromKeySecurityModule(spcData: Data, assetID: String) throws -> Data {
var ckcData: Data? = nil
var licenseURL : String?
licenseURL = DispatchQueue.main.sync {
var licenseURLForSelectedChannel = ""
if let keyWindow = UIWindow.key {
let menuViewController = keyWindow.rootViewController as! MenuSplitViewController
let playerController = menuViewController.viewControllers[1] as! DNSPlayerViewController
licenseURLForSelectedChannel = playerController.licenseURLForSelectedChannel() ?? ""
}
return licenseURLForSelectedChannel
}
guard licenseURL != nil else {
throw ProgramError.missingLicenseURL
}
guard let url = URL(string: licenseURLString) else {
print("Error! Invalid URL!") //Do something else
throw ProgramError.missingLicenseURL
}
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
request.httpBody = spcData
let postLength:NSString = NSString(data: spcData, encoding:String.Encoding.ascii.rawValue)!
request.setValue(String(postLength.length), forHTTPHeaderField: "Content-Length")
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.dataTask(with: request as URLRequest) { (responseData, _, error) -> Void in
ckcData = responseData
semaphore.signal()
}.resume()
semaphore.wait(timeout: .distantFuture)
guard ckcData != nil else {
throw ProgramError.noCKCReturnedByKSM
}
return ckcData!
}
func handleStreamingContentKeyRequest(keyRequest: AVContentKeyRequest) {
guard let contentKeyIdentifierString = keyRequest.identifier as? String,
let contentKeyIdentifierURL = URL(string: contentKeyIdentifierString),
let assetIDString = contentKeyIdentifierURL.host,
let assetIDData = assetIDString.data(using: .utf8)
else {
print("Failed to retrieve the assetID from the keyRequest!")
return
}
let provideOnlinekey: () -> Void = { () -> Void in
do {
let applicationCertificate = try self.requestApplicationCertificate()
let completionHandler = { [weak self] (spcData: Data?, error: Error?) in
guard let strongSelf = self else { return }
if let error = error {
keyRequest.processContentKeyResponseError(error)
return
}
guard let spcData = spcData else { return }
do {
// Send SPC to Key Server and obtain CKC
let ckcData = try strongSelf.requestContentKeyFromKeySecurityModule(spcData: spcData, assetID: assetIDString)
/*
AVContentKeyResponse is used to represent the data returned from the key server when requesting a key for
decrypting content.
*/
let keyResponse = AVContentKeyResponse(fairPlayStreamingKeyResponseData: ckcData)
/*
Provide the content key response to make protected content available for processing.
*/
keyRequest.processContentKeyResponse(keyResponse)
} catch {
keyRequest.processContentKeyResponseError(error)
}
}
keyRequest.makeStreamingContentKeyRequestData(forApp: applicationCertificate,
contentIdentifier: assetIDData,
options: [AVContentKeyRequestProtocolVersionsKey: [1]],
completionHandler: completionHandler)
} catch {
keyRequest.processContentKeyResponseError(error)
}
}
provideOnlinekey()
}
}
should look more or less like this:
function TContentKeyDelegate.requestApplicationCertificate(): NSData;
var
http: THTTPClient;
Response: TMemoryStream;
begin
http := THTTPClient.Create;
Response := TMemoryStream.Create;
try
http.ContentType := 'application/octet-stream';
http.Get(FAIRLPLAY_SERVER_URL, Response);
result := TNSData.Wrap(TNSData.OCClass.dataWithBytes(response.Memory, response.Size))
finally
Response.Free;
http.Free;
end;
end;
function TContentKeyDelegate.requestContentKeyFromKeySecurityModule(spcData: NSData; assetID: NSString): NSData;
var
http: THTTPClient;
Response: TMemoryStream;
Request: TMemoryStream;
begin
http := THTTPClient.Create;
Response := TMemoryStream.Create;
Request := TMemoryStream.Create;
Request.Write(spcData.bytes^, spcData.length);
try
Request.Position := 0;
http.ContentType := 'application/octet-stream';
http.Post(KEY_SERVER_URL, Request, Response);
result := TNSData.Wrap(TNSData.OCClass.dataWithBytes(response.Memory, response.Size))
finally
Request.Free;
Response.Free;
http.Free;
end;
end;
procedure TContentKeyDelegate.requestCompleteHandler(contentKeyRequestData: NSData;error: NSError);
var ckcData: NSData;
keyResponse: AVContentKeyResponse;
begin
ckcData := requestContentKeyFromKeySecurityModule(contentKeyRequestData, FAssetIDString);
keyResponse := TAVContentKeyResponse.Wrap(TAVContentKeyResponse.OCClass.contentKeyResponseWithFairPlayStreamingKeyResponseData(ckcData));
FKeyRequest.processContentKeyResponse(keyResponse);
end;
procedure TContentKeyDelegate.handleStreamingContentKeyRequest(keyRequest: AVContentKeyRequest);
var
contentKeyIdentifierString: NSString;
assetIDData: NSData;
contentKeyIdentifierURL: NSURL;
dictionary: NSDictionary;
begin
FKeyRequest := keyRequest;
contentKeyIdentifierString := TNSString.Wrap(keyRequest.identifier);
contentKeyIdentifierURL := TNSUrl.Wrap(TNSUrl.OCClass.URLWithString(contentKeyIdentifierString));
FAssetIDString := contentKeyIdentifierURL.host;
assetIDData := FAssetIDString.dataUsingEncoding(NSUTF8Stringencoding);
dictionary := TNSDictionary.Wrap(TNSDictionary.OCClass.dictionaryWithObject(TNSNumber.OCClass.numberWithInt(1), NSObjectToID(AVContentKeyRequestProtocolVersionsKey)));
keyRequest.makeStreamingContentKeyRequestDataForApp(
requestApplicationCertificate,
assetIDData,
dictionary,
requestCompleteHandler);
end;
I can post the whole unit if somebody is interested in. Using it with the FMX.Media class is quite simple. All you need is to assign the asset with the ContentKeyManager:
LAsset := TAVURLAsset.Wrap(TAVURLAsset.OCClass.URLAssetWithURL(LURL, nil));
if LAsset.hasProtectedContent then ContentKeyManager.addContentKeyRecipient(LAsset);
FPlayerItem := TAVPlayerItem.Wrap(TAVPlayerItem.OCClass.playerItemWithAsset(LAsset));