i'm trying to play an AES encrypted stream in AVPlayer.. typically a link of the key is delivered to the player inside the M3U8 playlist.. in my scenario the key is divided in half.. the first half is delivered by the server and i should append the other half inside the app to decrypt when playing
i've already done this on Android, is there a way to do it also on iOS?
This is the playlist:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=200000,RESOLUTION=284x160
chunklist_w670540365_b200000.m3u8?t=57b5b16d3824d
#EXT-X-STREAM-INF:BANDWIDTH=850000,RESOLUTION=640x360
chunklist_w670540365_b850000.m3u8?t=57b5b16d3824d
And this is the chunk list:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:13544
#EXT-X-KEY:METHOD=AES-128,URI="http://example.com/api/getEncryptionKey?t=57b5b16d3824d"
#EXTINF:9.6,
media_w670540365_b200000_13544.ts?t=57b5b16d3824d
#EXTINF:9.6,
media_w670540365_b200000_13545.ts?t=57b5b16d3824d
#EXTINF:10.56,
media_w670540365_b200000_13546.ts?t=57b5b16d3824d
This is what AVPlayer does:
1- the playlist gets downloaded and a chunk list is selected 2- the player downloads the chunk list 3- the decryption key to decrypt the chunks is downloaded 4- the player begins downloading the chunks sequentially to play them 5- every chunk is decrypted and played
What i need to do is: after the 3rd step when the player calls the api to get the encryption key using this link: 'http://example.com/api/getEncryptionKey?t=57b5b16d3824d', i want to intercept the response and append the other half of the key
Is it possible?
yes, it is very much possible! I recently did it in one of my projects.
Whenever AVPlayer
loads the encrypted video, it tries to load decryption key from the URL mentioned in prog_index.m3u8. If AVPlayer is not able to play video with the fetched key or if it didn't get the key at all on the specified url, it calls a delegate method from AVAssetResourceLoaderDelegate
that is
public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForRenewalOfRequestedResource renewalRequest: AVAssetResourceRenewalRequest) -> Bool {
return shouldLoadOrRenewRequestedResource(resourceLoadingRequest: renewalRequest)
}
and,
public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
return shouldLoadOrRenewRequestedResource(resourceLoadingRequest: loadingRequest)
}
which of course differ in the cases they are being called. Prior one is called when the player should wait for loading resource and later one is called when the player needs to renew the resource.
func shouldLoadOrRenewRequestedResource(resourceLoadingRequest: AVAssetResourceLoadingRequest) -> Bool {
guard var url = resourceLoadingRequest.request.url else {
return false
}
//FETCH THE KEY FROM NETWORK CALL/KEYSTORE, CONVERT IT TO DATA AND FINISH LOADING OF RESOURCE WITH THAT DATA, IN YOUR CASE JOIN THE OTHER HALF OF THE KEY TO ACTUAL KEY (you can get the first half from the url above)
resourceLoadingRequest.dataRequest?.respond(with: keyData)
resourceLoadingRequest.finishLoading()
return true;
}}
Once you'll return true with the actual key, the video will be played instantly.
While trying with Azure Media services the following sample works fine. Here we are adding the token as part of AVURLAsset options.
var options = [String: [String: String]]()
if (!token.isEmpty) {
let headers = ["Authorization": "Bearer " + token!]
options = ["AVURLAssetHTTPHeaderFieldsKey": headers]
}
let avAsset = AVURLAsset(url: videoUrl, options: options)
let avItem = AVPlayerItem(asset: avAsset)
let player = AVPlayer(playerItem: avItem)
let playerFrame = view.viewWithTag(1)?.frame
controller.player = player
if (autoPlay.isOn) {
player.rate = 1
}
controller.view.frame = playerFrame ?? CGRect(x: 0, y: 0, width: view.frame.width , height: 250)
addChild(controller)
view.viewWithTag(1)?.addSubview(controller.view)
controller.didMove(toParent: self)
The complete working sample can be found from
https://github.com/Azure-Samples/media-services-3rdparty-player-samples/tree/master/src/avplayer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With