private void HandleStreamingContentKeyRequest(AVContentKeyRequest keyRequest)
        {
            var contentKeyIdentifierString = keyRequest.Identifier.ToString();

            if (string.IsNullOrEmpty(contentKeyIdentifierString))
            {
                Debug.WriteLine("Failed to retrieve the assetID from the keyRequest!");
                return;
            }

            var contentKeyIdentifierUrl = new NSUrl(contentKeyIdentifierString);
            var assetIdString           = contentKeyIdentifierUrl.Host;
            var assetIdData             = NSData.FromString(assetIdString, NSStringEncoding.UTF8);

            Action provideOnlineKey = () =>
            {
                var applicationCertificate = RequestApplicationCertificate();

                try
                {
                    var keys    = new[] { new NSString(AVContentKeyRequest.ProtocolVersions) };
                    var numbers = new NSMutableArray <NSNumber>();
                    numbers.Add(new NSNumber(1));
                    var objects = new NSObject[] { numbers };
                    var options = new NSDictionary <NSString, NSObject>(keys, objects);
                    keyRequest.MakeStreamingContentKeyRequestData(applicationCertificate, assetIdData, options, async(data, error) => {
                        var ckcData = await this.RequestContentKeyFromKeySecurityModule(data, assetIdString);

                        if (ckcData == null)
                        {
                            return;
                        }

                        var keyResponse = AVContentKeyResponse.Create(ckcData);

                        keyRequest.Process(keyResponse);
                    });
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Failed to make streaming content key request data: {ex.Message}");
                }
            };

            /*
             * When you receive an AVContentKeyRequest via -contentKeySession:didProvideContentKeyRequest:
             * and you want the resulting key response to produce a key that can persist across multiple
             * playback sessions, you must invoke -respondByRequestingPersistableContentKeyRequest on that
             * AVContentKeyRequest in order to signal that you want to process an AVPersistableContentKeyRequest
             * instead. If the underlying protocol supports persistable content keys, in response your
             * delegate will receive an AVPersistableContentKeyRequest via -contentKeySession:didProvidePersistableContentKeyRequest:.
             */
            if (ShouldRequestPersistableContentKey(assetIdString) || PersistableContentKeyExistsOnDisk(assetIdString))
            {
                try
                {
                    NSError error;
                    keyRequest.RespondByRequestingPersistableContentKeyRequest(out error);

                    if (error != null)
                    {
                        throw new Exception($"Error requesting persistable content key: {error.ToString()}");
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);

                    /*
                     * This case will occur when the client gets a key loading request from an AirPlay Session.
                     * You should answer the key request using an online key from your key server.
                     */
                    provideOnlineKey();
                }

                return;
            }

            try
            {
                provideOnlineKey();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }
        private void HandlePersistableContentKeyRequest(AVPersistableContentKeyRequest keyRequest)
        {
            /*
             * The key ID is the URI from the EXT-X-KEY tag in the playlist (e.g. "skd://key65") and the
             * asset ID in this case is "key65".
             */

            var contentKeyIdentifierString = keyRequest.Identifier as NSString;

            if (contentKeyIdentifierString == null)
            {
                Debug.WriteLine("Failed to retrieve the assetID from the keyRequest!");
                return;
            }

            var contentKeyIdentifierUrl = new NSUrl(contentKeyIdentifierString);
            var assetIdString           = contentKeyIdentifierUrl.Host;
            var assetIdData             = NSData.FromString(assetIdString, NSStringEncoding.UTF8);

            Action <NSData, NSError> completionHandler = async(data, error) =>
            {
                if (error != null)
                {
                    keyRequest.Process(error);
                    pendingPersistableContentKeyIdentifiers.Remove(assetIdString);
                    return;
                }

                if (data == null)
                {
                    return;
                }

                try
                {
                    var ckcData = await RequestContentKeyFromKeySecurityModule(data, assetIdString);

                    NSData persistentKey = keyRequest.GetPersistableContentKey(ckcData, null, out error);

                    WritePersistableContentKey(persistentKey, new NSString(assetIdString));

                    /*
                     * AVContentKeyResponse is used to represent the data returned from the key server when requesting a key for
                     * decrypting content.
                     */
                    var keyResponse = AVContentKeyResponse.Create(persistentKey);

                    /*
                     * Provide the content key response to make protected content available for processing.
                     */
                    keyRequest.Process(keyResponse);

                    string assetName    = string.Empty;
                    bool   assetRemoved = false;

                    if (contentKeyToStreamNameMap.TryGetValue(assetIdString, out assetName))
                    {
                        assetRemoved = contentKeyToStreamNameMap.Remove(assetIdString);
                    }

                    if (!string.IsNullOrWhiteSpace(assetName) && assetRemoved && !contentKeyToStreamNameMap.ContainsKey(assetIdString))
                    {
                        var userInfo = new Dictionary <string, object>();
                        userInfo["name"] = assetName;

                        var userInfoDictionary = NSDictionary.FromObjectsAndKeys(userInfo.Values.ToArray(), userInfo.Keys.ToArray());
                        NSNotificationCenter.DefaultCenter.PostNotificationName(ContentKeyDelegate.DidSaveAllPersistableContentKey, null, userInfoDictionary);
                    }

                    pendingPersistableContentKeyIdentifiers.Remove(assetIdString);
                }
                catch (Exception ex)
                {
                    pendingPersistableContentKeyIdentifiers.Remove(assetIdString);
                    Debug.WriteLine(ex.Message);
                }
            };

            try
            {
                var applicationCertificate = RequestApplicationCertificate();

                var keys    = new[] { new NSString(AVContentKeyRequest.ProtocolVersions) };
                var numbers = new NSMutableArray <NSNumber>();
                numbers.Add(new NSNumber(1));
                var objects = new NSObject[] { numbers };
                var options = new NSDictionary <NSString, NSObject>(keys, objects);

                if (PersistableContentKeyExistsOnDisk(assetIdString))
                {
                    var urlToPersistableKey = CreateUrlForPersistableContentKey(assetIdString);
                    var contentKey          = NSFileManager.DefaultManager.Contents(urlToPersistableKey.Path);

                    if (contentKey == null)
                    {
                        pendingPersistableContentKeyIdentifiers.Remove(assetIdString);

                        /*
                         * Key requests should never be left dangling.
                         * Attempt to create a new persistable key.
                         */
                        keyRequest.MakeStreamingContentKeyRequestData(applicationCertificate, assetIdData, options, completionHandler);

                        return;
                    }

                    /*
                     * Create an AVContentKeyResponse from the persistent key data to use for requesting a key for
                     * decrypting content.
                     */

                    var keyResponse = AVContentKeyResponse.Create(contentKey);
                    keyRequest.Process(keyResponse);

                    return;
                }

                keyRequest.MakeStreamingContentKeyRequestData(applicationCertificate, assetIdData, options, completionHandler);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Failure responding to an AVPersistableContentKeyRequest when attemping to determine if key is already available for use on disk. {ex.Message}");
            }
        }