Offline HLS Fairplay playback error when the app is closed, code 16227 - ios11

I'm implementing Offline Playback with HLS Fairplay following the demo in the FairPlay Streaming Server SDK v4.0.1 that uses AVContentSessionKey.
I download three contents, each content is downloaded and persisted correctly, both the .movpkg and its content key on the documents directory, when I turn off the WIFI these three contents downloaded plays correctly without any problems, before playing Im using this code:
let urlAsset = element.urlAsset!
ContentKeyManager.shared.contentKeySession.addContentKeyRecipient(urlAsset)
if !urlAsset.resourceLoader.preloadsEligibleContentKeys {
urlAsset.resourceLoader.preloadsEligibleContentKeys = true
}
self.present(playerViewController, animated: true, completion: {
AssetPlaybackManager.sharedManager.setAssetForPlayback(urlAsset)
})
So far so good. But the problem is when I close the application (Home button to close applications) and then play the downloaded contents, only the last content downloaded plays correctly, the other ones (first and second) send these error on the console.
Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed"
UserInfo={NSUnderlyingError=0x1c065d760 {Error Domain=NSOSStatusErrorDomain Code=-16227 "(null)"},
NSLocalizedFailureReason=An unknown error occurred (-16227),
NSURL=file:///private/var/mobile/Containers/Data/Application/A950D8DB-B711-47E3-AAF5-C95CC9682430/Library/com.apple.UserManagedAssets.kkG8Ih/644986_7798B8476A473F68.movpkg/, NSLocalizedDescription=The operation could not be completed}
I double check the .movpkg with the keys in the documents directory and appears correctly
/Documents/.keys/one-key
/Documents/.keys/two-key
/Documents/.keys/three-key
Before the error occurs the ContentKeyDelegate is called and the key is loaded and passed to the request correctly.
if persistableContentKeyExistsOnDisk(withContentKeyIdentifier: assetIDString) {
let urlToPersistableKey = urlForPersistableContentKey(withContentKeyIdentifier: assetIDString)
guard let contentKey = FileManager.default.contents(atPath: urlToPersistableKey.path) else {
/
pendingPersistableContentKeyIdentifiers.remove(assetIDString)
return
}
/
Create an AVContentKeyResponse from the persistent key data to use for requesting a key for
decrypting content.
*/
let keyResponse = AVContentKeyResponse(fairPlayStreamingKeyResponseData: contentKey)
/
keyRequest.processContentKeyResponse(keyResponse)
return
}
If I print the contentKeyRecipients the three contents appears correctly
- (lldb) po
ContentKeyManager.shared.contentKeySession.contentKeyRecipients ▿ 3
elements
- 0 : AVURLAsset: 0x1c0234d40, URL = file:///private/var/mobile/Containers/Data/Application/E791A4DE-4261-46B7-A84D-D10B27035FAE/Library/com.apple.UserManagedAssets.kkG8Ih/539628_20469336224AA388.movpkg
- 1 : AVURLAsset: 0x1c0234fa0, URL = file:///private/var/mobile/Containers/Data/Application/E791A4DE-4261-46B7-A84D-D10B27035FAE/Library/com.apple.UserManagedAssets.kkG8Ih/644986_7798B8476A473F68.movpkg
- 2 : AVURLAsset: 0x1c42391c0, URL = file:///private/var/mobile/Containers/Data/Application/E791A4DE-4261-46B7-A84D-D10B27035FAE/Library/com.apple.UserManagedAssets.kkG8Ih/573744_62377F9549C45B93.movpkg
My tests are in iOS 11.1.2 and iOS 11.2 beta 2
I'm not sure what is happening, but seems to be a problem with the persisted key, I don't how if each content needs to be associated with one AVContentKeySession at time.
If someone faced a similar problem, any help would be appreciated.
Thanks in advance

I'm having similar issue.
however, since I need to support iOS 10, I'm not using the new AVContentKeyResponse class. Instead, I'm loading the persistent content key myself, and pass it to the loading request.
Anyway, I'm getting exact the same error as you and same behavior. One thing to note is that if I remove the code that loads persistent content key from disk, and always fetch the key from server, then everything works. But this defeats the purpose of "offline" playback...
So it seems like the system thinks the persistent content key is invalid...

Which TLLV you used on the server side to specify Rental Duration of the downloaded content? Did you use Content key duration TLLV or Offline Key TLLV? If you used Offline Key TLLV you need to double check that "Content ID" field is different for every downloaded movie.

We had encounter this error message, too.
It will happen when content exceed over expiration date which set in server side.
For example :
We give 10 minutes of expiration date for Video A
Download this Video A, and verify CKC delivery correctly (print log)
Play Video A without connection
Take a break (after 11 minutes), close App, and launch App again, select Video A to Play
Show below error message from AVPlayerItem.error.description:
Error Domain=AVFoundationErrorDomain Code=-11800
"The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (-16227),
NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x1d4257310
{Error Domain=NSOSStatusErrorDomain Code=-16227 "(null)"}}
You can refresh encrypted data again by
AVAssetResourceLoaderDelegate
or use AVContentSessionKey
Reference : https://developer.apple.com/videos/play/wwdc2018/507/

Make sure you set correct offline content identifier on a serverside. The identifier you set should be associated with the specific rendition/stream allowed by the license. This helped me.

Related

cypress not resolving localstorage item, although it shows on local storage

I'm trying to test my react application. And some data are saved in the local storage, and I want to make sure that these are working. So I started writing tests with cypress. Really cool library, it was so fun that I already wrote ~50 tests. But it started showing problems with local storage.
My code:
describe("delete account",()=>{
it("delete",()=>{
cy.visit("/")
assert.equal(localStorage.getItem("---current---"), null)
const username = 'abcd1234'
cy.get('[data-cy=username-input]').click().type(username)
cy.get('[data-cy=login-button]').click()
cy.wait(4*1000)
cy.log({...localStorage})
// assert.equal(localStorage.getItem(currentPlayerLS), username)
})
})
My goal was to check when the user logs in, it gets the local storage and checks if the ---current--- player value matches or not. But it raises an exception saying expected null to equal 'abcd1234'
I guessed there was some issue with resolving, so I even added a delay of 4 seconds.
I also logged the whole {...localSotage} says it is an empty dictionary. But the local storage says it has some value stored there.
I'm not sure how to handle it!! Can anyone help me?
Here is the snap:
The log at cy.log({...localStorage}) takes it's value before the test runs.
You should use this to get the value after the login.
cy.then(() => cy.log({...localStorage}))
As for the final assert, try directly using the key ---current--- in case currentPlayerLS is something else (some indication this is so).
assert.equal(localStorage.getItem('---current---'), username)

How to get Hikvision DeepinViews license plate number from URL?

I cant find the solution anywhere and mine doesn't seem to work.
I just want to see the last plate string in the browser,or the few last plates,doesn't matter.
http://login:password#MY.IP/ISAPI/Traffic/channels/1/vehicleDetect/plates/
<AfterTime><picTime>2021-12-09T09:07:15Z</picTime></AfterTime>
I do have a plate taken exactly at the time im using in pictime,but the result im getting is;
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ResponseStatus xmlns="
http://www.hikvision.com/ver20/XMLSchema
" version="2.0">
<requestURL>
/ISAPI/Traffic/channels/1/vehicleDetect/plates/
<AfterTime>
<picTime>2021-12-09T09:01:15Z</picTime>
</AfterTime>
</requestURL>
<statusCode>4</statusCode>
<statusString>Invalid Operation</statusString>
<subStatusCode>invalidOperation</subStatusCode>
</ResponseStatus>
POSTMAN
Edit:
Are you certain that the ISAPI setting is enabled in the camera configuration?
It's not possible in the browser without some tool to send and process your API request.
Have you tried using Postman?
Don't forget to use a Digest Auth header.
from requests.auth import HTTPDigestAuth
import requests
url = 'http://<Your IP>/ISAPI/Traffic/channels/1/vehicleDetect/plates/'
data = "<AfterTime><picTime>20220912T192011+0400</picTime></AfterTime>"
r=requests.get(url, data =data,auth=HTTPDigestAuth('admin', 'password'))
print(r.text)
Try this one after enabling this setting in camera
Screenshot

Spontaneous Server Errors During AngularJS $http calls

I'm building an SPA in AngularJS served by a Laravel (5.1) backend. Of late I've been encountering an annoying error, a server 500 or code 0 error which is abit hard to explain how it comes but let me try to may be someone will understand the dental formula of my problem.
When i start my AngularJS controller, I make several server calls (via independent $http calls from services) to retrieve information i might later need in the controller. For example,
Functions.getGrades()
.then(function(response)
{
$scope.grades = response.data;
});
Subjects.offered()
.then(function(response)
{
$scope.subjects = response.data;
});
Later on i pass these variables (grades or subjects) to a service where they are used for processing. However, these functions are randomly returning code 500 server errors after they run, and sometimes returning status code 0 after running. This happens in a random way and it is hard for me to point out the circumstances leading to their popping up. This leaves me with frequent empty Laravel-ised error screens like the ones shown below.
Anyone reading my mind?
Ok, after a suggestion given in a comment above that I check my Laravel log files (located in storage/logs/laravel.log- Laravel 5.1), i found out that the main error most of these times was this one: 'PDOException' with message 'SQLSTATE[HY000] [1044] Access denied for user ''#'localhost' to database 'forge'' in ..., plus another one that paraphrased something like No valid encrypter found. These were the key opener.
On reading another SO thread here, it said in part:
I solved, sometimes laravel not read APP_KEY in .ENV. And returns a value "SomeRandomString" (default is defined in config / app.php), and have the error "key length is invalid", so the solution is to copy the value of APP_KEY, to the value 'key 'in config / app.php, that's all! I solved!
That was exactly the issue! When loading the DB params from the .env to config/database.php, Laravel was sometimes unable to read the environment variables and went for the fallback default fallback options (forge for DB name and username and SomeRandomString for the APP_KEY). So, to solve this i just did as advised: copied the APP_KEY in .env to the config/app.php and edited the default DB parameters to the actual DB name and username/password I'm using. Just that and i was free from pollution. Hope someone finds this helpful.

How to view JSON logs of a managed VM in the Log Viewer?

I'm trying to get JSON formatted logs on a Compute Engine VM instance to appear in the Log Viewer of the Google Developer Console. According to this documentation it should be possible to do so:
Applications using App Engine Managed VMs should write custom log
files to the VM's log directory at /var/log/app_engine/custom_logs.
These files are automatically collected and made available in the Logs
Viewer.
Custom log files must have the suffix .log or .log.json. If the suffix
is .log.json, the logs must be in JSON format with one JSON object per
line. If the suffix is .log, log entries are treated as plain text.
This doesn't seem to be working for me: logs ending with .log are visible in the Log Viewer, but displayed as plain text. Logs ending with .log.json aren't visible at all.
It also contradicts another recent article that states that file names must end in .log and its contents are treated as plain text.
As far as I can tell Google uses fluentd to index the log files into the Log Viewer. In the GitHub repository I cannot find any evidence that .log.json files are being indexed.
Does anyone know how to get this working? Or is the documentation out-of-date and has this feature been removed for some reason?
Here is one way to generate JSON logs for the Managed VMs logviewer:
The desired JSON format
The goal is to create a single line JSON object for each log line containing:
{
"message": "Error occurred!.",
"severity": "ERROR",
"timestamp": {
"seconds": 1437712034000,
"nanos": 905
}
}
(information sourced from Google: https://code.google.com/p/googleappengine/issues/detail?id=11678#c5)
Using python-json-logger
See: https://github.com/madzak/python-json-logger
def get_timestamp_dict(when=None):
"""Converts a datetime.datetime to integer milliseconds since the epoch.
Requires special handling to preserve microseconds.
Args:
when:
A datetime.datetime instance. If None, the timestamp for 'now'
will be used.
Returns:
Integer time since the epoch in milliseconds. If the supplied 'when' is
None, the return value will be None.
"""
if when is None:
when = datetime.datetime.utcnow()
ms_since_epoch = float(time.mktime(when.utctimetuple()) * 1000.0)
return {
'seconds': int(ms_since_epoch),
'nanos': int(when.microsecond / 1000.0),
}
def setup_json_logger(suffix=''):
try:
from pythonjsonlogger import jsonlogger
class GoogleJsonFormatter(jsonlogger.JsonFormatter):
FORMAT_STRING = "{message}"
def add_fields(self, log_record, record, message_dict):
super(GoogleJsonFormatter, self).add_fields(log_record,
record,
message_dict)
log_record['severity'] = record.levelname
log_record['timestamp'] = get_timestamp_dict()
log_record['message'] = self.FORMAT_STRING.format(
message=record.message,
filename=record.filename,
)
formatter = GoogleJsonFormatter()
log_path = '/var/log/app_engine/custom_logs/worker'+suffix+'.log.json'
make_sure_path_exists(log_path)
file_handler = logging.FileHandler(log_path)
file_handler.setFormatter(formatter)
logging.getLogger().addHandler(file_handler)
except OSError:
logging.warn("Custom log path not found for production logging")
except ImportError:
logging.warn("JSON Formatting not available")
To use, simply call setup_json_logger - you may also want to change the name of worker for your log.
I am currently working on a NodeJS app running on a managed VM and I am also trying to get my logs to be printed on the Google Developper Console. I created my log files in the ‘/var/log/app_engine’ directory as described in the documentation. Unfortunately this doesn’t seem to be working for me, even for the ‘.log’ files.
Could you describe where your logs are created ? Also, is your managed VM configured as "Managed by Google" or "Managed by User" ? Thanks!

Python Google appengine 'Attachment' object does not support indexing

Since sometime after 3pm EST on January 9th I am getting
TypeError: 'Attachment' object does not support indexing errors when trying to access the data portion of an email attachment:
attach = mail_message.attachments.pop()
encodedAttachment = attach[1]
The format of the emails I am processing has not changed in that time, and this code worked flawlessly up until then
The latest version (1.8.9) has introduced an Attachment class that is returned now instead of the (filename content) tuple that was returned previously. The class does implement __iter__, so unpacking works exactly the same:
filename, content = attachment
But it doesn't implement __getitem__, so accessing via index as you're doing will cause the error you're seeing. It's possible that creating an issue will get the code changed to be completely backwards-compatible, but the practical thing would be to change your code.

Resources