Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content protection errors are never forwarded to AVPlayer #3

Open
defagos opened this issue Nov 29, 2018 · 3 comments
Open

Content protection errors are never forwarded to AVPlayer #3

defagos opened this issue Nov 29, 2018 · 3 comments
Labels
help wanted Extra attention is needed maintenance

Comments

@defagos
Copy link
Member

defagos commented Nov 29, 2018

Due to an Apple AVFoundation bug, calling [AVAssetResourceLoadingRequest finishLoadingWithError:] from a resource loader delegate implementation to report an error does not correctly forward this error information to the AVPlayer.

Instead, the original error is somehow internally (and incorrectly) transformed into another error. If the code used for the original error is by any chance a known error from the NSPOSIXErrorDomain domain, the error is for example turned into an NSPOSIXErrorDomain with the same code. The original domain and the associated user info dictionary are completely lost in the process. This new incorrect error is then attached to the AVPlayerItem and can be read after its state changed to AVPlayerItemStatusFailed (observed by KVO).

The errorLog attached to the item is empty and is therefore not helpful.

We should file a bug report for Apple about this issue.

Possible workaround

A possible workaround would be to access the resource loader attached to an AVURLAsset with -[AVPlayerItem asset] (cast to AVURLAsset) and the resourceLoader.delegate path, after the status changed to AVPlayerItemStatusFailed. Of course, since there is no error property on the delegate, being able to read it in SRG Media Player would require this library to define a protocol, which is probably overkill and ugly.

Consequences

  • The content protection error domain and codes were made public. This has been reverted since these errors cannot be seen outside at the moment (see commit b3a0163). Publishing them would be misleading.
  • The similar fake content protection commit has been hard-reverted as well and cannot be seen anymore.
  • There is currently no way to catch resource loading issues at the AVPlayer or SRGMediaPlayerController level properly. There is therefore no way to implement dedicated instruction messages at the moment.

Improvements if fixed

If Apple fixes this bug, we can make the error header public.

@defagos defagos added help wanted Extra attention is needed maintenance labels Nov 29, 2018
@defagos defagos changed the title SRG Content Protection errors are never received by AVPlayer Content protection errors are never forwarded to AVPlayer Nov 30, 2018
@defagos
Copy link
Member Author

defagos commented Jun 29, 2022

I discovered this issue has been fixed in iOS 15. This requires two things, though:

  • The error code must be an Int (for Swift errors this means the enum must be an Int enum).
  • The error code must be different from 0 (e.g. I picked 1 in the examples below).

If both conditions are met the error including its localized description are retrieved from the player item when its status changed to failed:

Error Domain=ch.srgssr.resource-loader Code=1 "Cannot load resource, dude" UserInfo={NSDescription=Cannot load resource, dude}

Failing to fulfill any of these requirements leads to an anonymous error:

Error Domain=CoreMediaErrorDomain Code=-12882 "(null)"

On iOS 14 the error code is received but the message is still lost:

Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (1), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x600003259200 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

Check the attached sample project.

@defagos
Copy link
Member Author

defagos commented Oct 14, 2022

Update: This does not suffice. If loading custom://server/content the error is not propagated, but if loading custom://server/content.m3u8 instead the error is correctly propagated.

Maybe the content type cannot be inferred without extension and should be provided explicitly to the information request. If we cannot find a way we still can cheat by adding a dummy extension to the URLs we load. Does not make a difference apparently

@defagos
Copy link
Member Author

defagos commented Oct 24, 2022

Conditions for correct error propagation changed during iOS 16.1 betas but the RC made changes again. The best way to throw errors from a resource loader, either from Objective-C or Swift code, is the following:

  • The error must be an NSError.
  • Its code must be > 0.
  • The message must be provided in the userInfo dictionary as usual.

Note that the error received on the AVPlayerItem error contains the message under an NSDescription key instead of NSLocalizedDescription. Also note that the error must be built as an NSError from the start, conversion with as NSError does not work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed maintenance
Projects
None yet
Development

No branches or pull requests

1 participant