FairPlay Streaming

RSS for tag

Securely deliver streaming media to devices through the HTTP Live Streaming protocol using FairPlay Streaming (FPS).

FairPlay Streaming Documentation

Posts under FairPlay Streaming tag

45 Posts
Sort by:
Post not yet marked as solved
0 Replies
447 Views
I've been encountering a substantial increase in the following error log and am eager to find its root cause. The pattern of these logs emerge predominantly when attempting to play downloaded FPS DRM files(MOVPKG files). Except for a few rare instances, most occurrences are associated with content downloaded in previous OS versions, leading to playback issues following recent OS updates. The error log I've been encountering is as follows: Error Domain=CoreMediaErrorDomain Code=-16845 "HTTP 400: (unhandled)" Even after searching, there are hardly any cases available, and the only thing I found is these issues https://github.com/jhomlala/betterplayer/issues?q=is%3Aissue+16845+is%3Aclosed I've been advising users to delete and re-download the affected content, which, in all cases, results in successful playback. I'm seeking advice from anyone who might have experienced similar issues. If you've encountered a comparable situation or have any suggestions, I would greatly appreciate your input.
Posted Last updated
.
Post marked as solved
1 Replies
447 Views
My project is a TV player app for HLS streams with fairplay encryption. It is made on swiftUI for iPhone and iPad, it is in production. I have enabled the target "Mac (Designed for iPad)" in the project settings, and It is working perfectly on Mac M1 chips when running the app from the Mac AppStore. The Mac version has never been main main focus, but it is nice to have it working so easily. However when I run the app from Xcode, by selecting "My Mac (Designed for iPad)", everytime AVPlayer wants to start playback I am ejected from the app and the only thing I get from the logcat is: Message from debugger: Terminated due to signal 9 Why? And Why does it work when running the app published on the appstore? I was able to debug a bit and identify which line of code triggers the issue but I am still stuck: I am using an AVAssetResourceLoaderDelegate to load the Fairplay Keys instead of the default one (because I need some authentication parameters in the HTTP headers to communicate with the DRM Proxy). So, in the process I am able to request SPC data and CKC (I have verified the data), and then when the loadingRequest.finishLoading() is called.. BOOM the app is terminated and it triggers the log Message from debugger: Terminated due to signal 9. I am sharing the delegate method from the AVAssetResourceLoaderDelegate where it happens. This has been written a while ago and is running fine on all devices. If you are not used to this delegate, it is used by AVPlayer whenever a new mediaItem is set with the method: AVPlayer.replaceCurrentItem(with: mediaItem) func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool { guard let dataRequest = loadingRequest.dataRequest else { return false } getFairplaycertificate { data, _ in // Request Server Playback Context (SPC) data guard let certificate = data, let contentIdData = (loadingRequest.request.url?.host ?? "").data(using: String.Encoding.utf8), let spcData = try? loadingRequest.streamingContentKeyRequestData( forApp: certificate, contentIdentifier: contentIdData, options: [AVContentKeyRequestProtocolVersionsKey: [1]] ) else { loadingRequest.finishLoading(with: NSError(domain: "tvplayer", code: -1, userInfo: nil)) print("⚠️", #function, "Unable to get SPC data.") return false } // Now the CKC can be requested let networkId = loadingRequest.request.url?.host ?? "" self.requestCKC(spcData: spcData, contentId: networkId) { ckc, error in if error == nil && ckc != nil { // The CKC is correctly returned and is sent to AVPlayer. Stream is decrypted dataRequest.respond(with: ckc!) loadingRequest.contentInformationRequest?.contentType = AVStreamingKeyDeliveryContentKeyType loadingRequest.finishLoading() // <--- THIS LINE IS GUILTY!!! } else { print("⚠️", #function, "Unable to get CKC.") loadingRequest.finishLoading(with: error) } } return true } return true } If I comment loadingRequest.finishLoading() or if I replace it by: loadingRequest.finishLoading(with: error), the app is not terminated but my decryption keys are not loaded. That's the only clue I have so far. Any help would be appreciated. What should I look for? Is there a way to get a detailed error stacktrace? Thanks.
Posted
by kjvill.
Last updated
.
Post not yet marked as solved
0 Replies
314 Views
How to recognize #EXT-OATCLS-SCTE35 tag in live HLS playlist and also manifest has other custom tags. I have tried using timedMetadata property of AVPlayerItem , KVO approach. But it's not notifying the presence of this tag. Can someone help me in implementing this?
Posted Last updated
.
Post not yet marked as solved
0 Replies
439 Views
Our initial understanding was that this event is fired only when the DRM blocks the video playback. However, in the present case we see that it is called even when playback is successful(playback with external screen connected). To assess whether playback remains functional when the 'outputObscuredDueToInsufficientExternalProtection' event is triggered, we conducted two specific scenario tests: 1) playing an asset without any DRM restrictions, and 2) playing an asset with DRM restrictions. Result: In our analysis, we have identified that the 'outputObscuredDueToInsufficientExternalProtection' flag always remains set to one, even when playback is successful. However, it is expected to be set to zero when the playback is successful. working case log when playback is successful: default 13:23:19.096682+0530 AMC ||| observeValueForKeyPath = "outputObscuredDueToInsufficientExternalProtection" object = <AVPlayer: 0x281284930> change kind = { kind = 1; new = 1; old = 0; } non working case log when playback came as black screen: default 13:45:21.356857+0530 AMC ||| observeValueForKeyPath = "outputObscuredDueToInsufficientExternalProtection" object = <AVPlayer: 0x281c071e0> change kind = {kind = 1; new = 1; old = 0; } We searched through related documents and conducted a Google search, but we couldn't find any information or references related to this behavior of the 'outputObscuredDueToInsufficientExternalProtection' event. It would be really appreciated if any one can help us with this!
Posted
by vinay1234.
Last updated
.
Post not yet marked as solved
0 Replies
386 Views
We have a logic in the SDK which stops playback when the outputObscuredDueToInsufficientExternalProtection event is fired by the player. Our initial understanding was that this event is fired only when the DRM blocks the video playback. However, in the present case we see that it is called even when playback is successful(playback with external screen connected). To determine whether playback still functions when the 'outputObscuredDueToInsufficientExternalProtection' event is triggered, we temporarily disabled the playback stop implementation that occurs after the event is triggered. code snippet - Observations - After this event was triggered during mirroring playback using a Lightning to HDMI connector, our expectation was that the playback would result in a black screen. However, to our surprise, the playback worked perfectly, indicating that this event is being triggered even when there are no DRM restrictions for that asset's playback. Another scenario we tested involved using a VGA connector. In this case, we observed that the 'outputObscuredDueToInsufficientExternalProtection' event was triggered. Initially, playback started as expected when we commented out the playback stop implementation. However, after a few seconds of playback, the screen went black. In the first scenario, it was unexpected for the 'outputObscuredDueToInsufficientExternalProtection' event to trigger, as the playback worked without issues even after the event was triggered. However, in the second scenario, the event was triggered as expected. The issue we identified is that this event is being triggered irrespective of the presence of DRM restrictions for the asset. In another scenario, we attempted to differentiate between the VGA and HDMI connectors to determine if such distinction was possible. However, we found that the VGA cable was also recognized as an HDMI port in the case of iOS. We also tested the issue on an older iOS version (iOS 14.6.1) to see if the problem persisted. Surprisingly, we found that the 'outputObscuredDueToInsufficientExternalProtection' event was triggered even in the older OS version. Conclusion: In our analysis, we have identified that the 'outputObscuredDueToInsufficientExternalProtection' flag always remains true even though output is not obsecured. working case log: default 13:23:19.096682+0530 AMC ||| observeValueForKeyPath = "outputObscuredDueToInsufficientExternalProtection" object = <AVPlayer: 0x281284930> change kind = { kind = 1; new = 1; old = 0; } non working case log: default 13:45:21.356857+0530 AMC ||| observeValueForKeyPath = "outputObscuredDueToInsufficientExternalProtection" object = <AVPlayer: 0x281c071e0> change kind = {kind = 1; new = 1; old = 0; } We searched through related documents and conducted a Google search, but we couldn't find any information or references related to this behavior of the 'outputObscuredDueToInsufficientExternalProtection' event. It would be really appreciated if any one can help us with this!
Posted
by vinay1234.
Last updated
.
Post not yet marked as solved
0 Replies
512 Views
Hi there, I want to play a stream of audio immediately after the first chunk of the audio arrives. The data stream looks like this Audio_data, Delimiter, Json_data. currently I am handling all chunks before the delimiter and adds it in the queue of the AVQueuePlayer. However, when playing this audio during the stream there are many glitches and does not work well. Waiting until all chunks arrived and then play the audio works well. So I assume there is no problem with the audio data, but with the handling of the chunks as they come and play immediately. Happy about any advice you have! I am pretty lost right now. Thank you so much. import SwiftUI import AVFoundation struct AudioStreamView: View { @State private var players: [AVAudioPlayer] = [] @State private var jsonString: String = "" @State private var queuePlayer = AVQueuePlayer() var streamDelegate = AudioStreamDelegate() var body: some View { VStack(spacing: 20) { Button("Fetch Stream") { fetchDataFromServer() } .padding() TextEditor(text: $jsonString) .disabled(true) .border(Color.gray) .padding() .frame(minHeight: 200, maxHeight: .infinity) } } func fetchDataFromServer() { guard let url = URL(string: "https://dev-sonia.riks0trv4c6ns.us-east-1.cs.amazonlightsail.com/voiceMessage") else { return } var request = URLRequest(url: url) request.httpMethod = "POST" // Specify the request type as POST let parameters: [String: Any] = [ "message_uuid": "value1", "user_uuid": "68953DFC-B9EA-4391-9F32-0B36A34ECF56", "session_uuid": "value3", "timestamp": "value4", "voice_message": "Whats up?" ] request.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: .fragmentsAllowed) request.addValue("application/json", forHTTPHeaderField: "Content-Type") let task = URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) in guard let strongSelf = self else { return } if let error = error { print("Error occurred: \(error)") return } // You might want to handle the server's response more effectively based on the API's design. // For now, I'll make an assumption that the server returns the audio URL in the response JSON. if let data = data { do { if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let audioURLString = jsonResponse["audioURL"] as? String, let audioURL = URL(string: audioURLString) { DispatchQueue.main.async { strongSelf.playAudioFrom(url: audioURL) strongSelf.jsonString = String(data: data, encoding: .utf8) ?? "Invalid JSON" } } else { print("Invalid JSON structure.") } } catch { print("JSON decoding error: \(error)") } } } task.resume() } func playAudioFrom(url: URL) { let playerItem = AVPlayerItem.init(url: url) queuePlayer.replaceCurrentItem(with: playerItem) queuePlayer.play() } }
Posted
by dustin_kl.
Last updated
.
Post not yet marked as solved
0 Replies
316 Views
On the FairPlay main page it states: The FPS Deployment Package is not available to third parties acting on behalf of licensed content owners. Could someone please provide more details around this statement? If I were to build a subscription based platform where users can upload & monetize their videos, and used FairPlay to prevent unauthorized access to the creator's content, what would Apple's response be?
Posted
by TinoF.
Last updated
.
Post not yet marked as solved
0 Replies
365 Views
It's been over a month since I requested an FPS Deployment Package, and the only response I've gotten is a case number and an email stating that a representative will check in and get back to me, usually on Wednesday. I'm wondering if I need to do anything further or if cases like mine are common.
Posted
by alskapark.
Last updated
.
Post not yet marked as solved
0 Replies
369 Views
Hello, I am interested in developing an iOS app that can monitor and potentially block third-party applications while a specific app is running. I would like to inquire about the feasibility of implementing such functionality within the iOS ecosystem and if there are any privacy terms or restrictions that I need to be aware of to ensure compliance with Apple's policies. Thank you for your guidance.
Posted Last updated
.
Post not yet marked as solved
0 Replies
352 Views
Case-ID: 3540728, we have developer membership, we have applied for fps on 31st July, and it was acknowledged from apple end, it was expected to be done in a week, although despite of many reminders we still have not got any response from apple reviewing team. can anyone have idea about why its taking so long. any help is appreciated.
Posted Last updated
.
Post not yet marked as solved
3 Replies
1.2k Views
Hello, We are using HLS for our streaming iOS and tvOS applications. We have DRM protection on our applications but we want add another secure layer which is CDN token. We want to add that CDN token data on header or query parameters. Any of two are applicable at our CDN side. There is a problem at client side. We want to send that token knowledge and refresh at given a time. We add token data using at initial state let asset = AVURLAsset(url: url, options: ["AVURLAssetHTTPHeaderFieldsKey": headers]) and add interceptor with asset.resourceLoader.setDelegate. It works seamlessly. We use AVAssetResourceLoaderDelegate and we can intercept just master playlist and playlists via func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool and we can refresh CDN token data at only playlists. That token data can be at query params or header. It does not matter. For example, #EXTM3U #EXT-X-VERSION:3 #EXTINF:10.0 https://chunk1?cdntoken=A.ts #EXTINF:10.0 https://chunk2?cdntoken=A.ts #EXTINF:10.0 https://chunk3?cdntoken=A.ts #EXTINF:10.0 assume that it is our .m3u8 file for given live video playlist. It has three chunks with cdn token data in query params. If we give that chunks to AVPlayer. It is going to play chunks in order. When we change new cdn token at query params, it effects our chunk Urls and our player stalls. It is because our cdn adds new cdn token knowledge to chunk's Url. It means that our new .m3u8 is going to be like that for next playlist; #EXT-X-VERSION:3 #EXTINF:10.0 https://chunk4?cdntoken=B.ts #EXTINF:10.0 https://chunk5?cdntoken=B.ts #EXTINF:10.0 https://chunk6?cdntoken=B.ts #EXTINF:10.0 Cdn token data is converted to B from A at cdn side and it sends new playlist like that. That's why, our player is going to stall. Is there any way not to player stall with edited chunk url? When we change new cdn token at header. It does not change chunks url like at the first question but AVPlayer does not allow to intercept chunk Urls which means that before callin https://chunk1?cdntoken=A.ts url, i want to intercept and add new cdn token data to header. Is there any way to intercept chunk Urls like intercepting playlist? Thanks for answers in advance
Posted Last updated
.
Post not yet marked as solved
1 Replies
518 Views
Hi, we have hls+fps stream, on our app implementation through AVAssetResourceLoader (get spc, generate ckc correctly) and stream played successfully But when we try to download stream for offline, through session.processContentKeyRequest for contentId, we get spc, generate ckc the same as previously, but can't recieve persistent key data keyRequest.persistableContentKey PKD failed Error Domain=AVFoundationErrorDomain Code=-11835 "Cannot Open" UserInfo={NSLocalizedFailureReason=This content is not authorized., NSLocalizedDescription=Cannot Open, NSUnderlyingError=0x282da98f0 {Error Domain=NSOSStatusErrorDomain Code=-42668 "(null)"}} Server and client the same, fps stream played, but not load pkd for offline All offline part of sources we get from HLS Catalog example, and implement requestCertificate and requestContentKeyFromKeySecurityModule, and i don't understand why we not recieve pkd.
Posted
by Rastrelli.
Last updated
.
Post marked as solved
3 Replies
2.4k Views
Issue: I am supporting an iOS application that streams Fairplay DRM protected content. On iOS 16 devices, I am seeing intermittent exceptions thrown when trying to process the CKC returned by the license server. The thrown exception is as follows: -[AVContentKeyRequest processContentKeyResponse:] AVContentKeySession's keySystem is not same as that of keyResponse This issue does not occur on older devices (we support iOS 13, 14, 15) I am unable to find documentation about this error so any insight is appreciated: High-Level Code Overview Use ContentKeyRequest to request an application certificate Use returned Cert to call makeStreamingContentKeyRequestData Use returned data to request FairPlay license Use returned CKC to generate AVContentKeyResponse (i.e. AVContentKeyResponse(fairPlayStreamingKeyResponseData:_)) Call processContentKeyResponse(_) App crash/exception thrown when callling processContentKeyResponse I am seeing other issues related to DRM and iOS 16 but these are specific to downloaded and offline content which do not match my use case.
Posted Last updated
.
Post not yet marked as solved
1 Replies
724 Views
When i validated the VOD playlist with media stream validator, am getting the "Different target durations detected" error for trk vs sub, var vs sub playlists, Error: Different target durations detected --> Detail: Target duration: 3599 vs Target duration: 6 --> Source: subs/eus_2/playlist.m3u8 --> Compare: trk969287/playlist.m3u8 --> Detail: Target duration: 6 vs Target duration: 3599 --> Source: var969287/playlist.m3u8 --> Compare: subs/eus_2/playlist.m3u8 but the apple specification (https://developer.apple.com/documentation/http-live-streaming/hls-authoring-specification-for-apple-devices specification) stated that "5.7. For VOD content, target durations of subtitle playlists MAY be longer than the other media." Can you please clarify the query that why we are getting different target duration error for subtitle vs other media playlists even though the apple spec mentioned that the subtitle playlist may be longer than other media for VOD assets?
Posted Last updated
.
Post not yet marked as solved
0 Replies
502 Views
I need to correctly determine the mime type of keynote file and numbers file without relying on the extension. For this purpose, I am hoping to use the magic number concept and match it with the first four bytes of a file. Link for magic number understanding -> [https://www.outsystems.com/forge/component-overview/10108/validate-file-extension#:~:text=A%20magic%20number%20is%20a,types%20which%20is%20hexadecimal%20format.] Though after extensive searching online I am unable to find a unique magic number for the above files moreover first four bytes of the file is matching with the magic number of the zip file due to which I am getting the wrong extension as zip. This is the first four bytes 0x50, 0x4B, 0x3, 0x4. Is there any reliable way to find the mime type of these files without relying on an extension?
Posted Last updated
.
Post not yet marked as solved
1 Replies
961 Views
We have created a hls playback framework and lot of our client's are complaining about this error {"code": -19152, "domain": "CoreMediaErrorDomain", "localizedDescription": "The operation couldn’t be completed. (CoreMediaErrorDomain error -19152 - The operation couldn’t be completed. (CoreMediaErrorDomain error -19152.))", "localizedFailureReason": "", "localizedRecoverySuggestion": ""} We are unable to reproduce this issue on our end but we have data reflecting the same error happening at good rate. Any help/hint is welcome. Thanks
Posted Last updated
.
Post not yet marked as solved
0 Replies
503 Views
Hello everyone, I have captured SPC and CKC messages. I'm trying to parse it using verify_ckc tool, but I only get SPC encryption key and SPC encryption IV: CKC/SPC Sanity Test v. 2.01 ========================= Begin SPC Data =============================== SPC container size 7296 SPC Encryption Key - a9 a6 8c 2b 62 2f 3a ee bc 92 0c 4d cb 07 d1 c7 SPC Encryption IV - 75 7f f7 60 c9 d0 16 2a 7b 96 0e 42 e6 c3 3e 75 ================ SPC TLLV List ================ =========================== End SPC Data ================================= =========================== Begin CKC Data ================================= =========================== End CKC Data ================================= SPC binary message: https://www.icloud.com/iclouddrive/0c0hm06RJQpTlsWBB1ANb3OZw#SPC CKC binary message: https://www.icloud.com/iclouddrive/016apmD_MZDFaGVNey_HA_17g#CKC What is the problem?
Posted
by Reta_Hand.
Last updated
.