为什么我的AVPlayer无法正常工作?

vrw*_*wim 6 aes http-live-streaming ios avplayer

我无法连接到通过HLS与128位加密连接的实时流,它是一个Azure媒体流.服务器还需要一个授权令牌,该令牌通过HTTP头提供Authorization并且属于该类型Bearer <insert token here>.

我的代码是这样的:

let url = "http://<redacted>"

let headers = ["Authorization": "Bearer <token redacted>"]
let options = ["AVURLAssetHTTPHeaderFieldsKey": headers]

let avAsset = AVURLAsset(url: URL(string: url)!, options: options)
let avItem = AVPlayerItem(asset: avAsset)
player = AVPlayer(playerItem: avItem)

player.play()
Run Code Online (Sandbox Code Playgroud)

我调试了网络呼叫并AVPlayer发出了2个呼叫,一个是为了查看是否有新版本(我猜是从我在该呼叫上收到的304)和一个来获取流.这些调用分别以304 Not Modified和206 Partial Content返回.

这些电话:

304来电

206电话

我没有听到任何声音,但设备上的任何其他声音都被静音(应该如此).这告诉我播放接收的数据存在问题.我的同事可以在Android上加载流,只需要做我在这里做的事情,我可以在http://ampdemo.azureedge.net/azuremediaplayer.html加载它.

我通过提取来检查播放器的状态player.currentItem?.status,这是failed.该player.currentItem?.errorIS

错误域= AVFoundationErrorDomain代码= -11828"无法打开"UserInfo = {NSUnderlyingError = 0x60800005a610 {错误域= NSOSStatusErrorDomain代码= -12847"(null)"},NSLocalizedFailureReason =不支持此媒体格式.,NSLocalizedDescription =无法打开}

编辑: 我尝试进一步调试.我实现了,AVAssetResourceLoaderDelegate并在resourceLoader:shouldWaitForLoadingOfRequestedResource:我添加了以下代码:

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
    DispatchQueue.main.async {
        var request = loadingRequest.request

        var headers = request.allHTTPHeaderFields!
        if headers["Authorization"] == nil {
            headers["Authorization"] = "Bearer <token>"
        } else {
            print("Auth header exists: \(headers)")
        }

        request.url = URL(string: self.url)!
        request.allHTTPHeaderFields = headers

        URLSession(configuration: URLSessionConfiguration.default).dataTask(with: request) {
            data, response, error in

            if let error = error {
                print(error)
                loadingRequest.finishLoading(with: error)
            } else {
                loadingRequest.dataRequest?.respond(with: data!)
                loadingRequest.finishLoading()
            }
        }.resume()
    }

    return true
}
Run Code Online (Sandbox Code Playgroud)

我只在Authorization尚不存在时添加标题.我认为覆盖Authorization所有调用的标头可能会破坏加密.

因为resourceLoader:shouldWaitForLoadingOfRequestedResource:只有当请求使用除http和之外的方案时才会被调用https,所以我替换http://mycustomscheme://.这也是我在这里设置网址的原因,因为请求中的原始网址没有有效的网址方案.

这种方式对我来说更好,因为我可以查看请求和响应,因为它们正在发生.没有更多的Burp Suite可以调试这些电话.

我现在遇到的问题是我收到了我期望的数据(播放器确实执行了两次相同的请求),但是当我检查时player.currentItem?.status,这是failed.该player.currentItem?.errorIS

错误域= NSURLErrorDomain代码= -1001"请求超时." UserInfo = {NSLocalizedDescription =请求超时.,NSUnderlyingError = 0x60000005f320 {错误域= NSOSStatusErrorDomain代码= -1001"(null)"}}

由于Android和Web版本的运行没有问题,因此对我来说似乎很奇怪.

我查看了Android代码,<url>.ism/manifest(format=m3u8-aapl-v3)而不是仅仅使用<url>.ism/manifest.如果我使用该URL,我会获得相同的failed状态,但错误为

错误域= AVFoundationErrorDomain代码= -11800"操作无法完成"UserInfo = {NSUnderlyingError = 0x608000059e60 {错误域= NSOSStatusErrorDomain代码= -12936"(null)"},NSLocalizedFailureReason =发生未知错误(-12936),NSLocalizedDescription =操作无法完成}

好吧,我让它工作,但我不知道它为什么工作,为什么它不起作用.我输入了Android执行的URL作为获取流的第二个调用,这个URL嵌入了质量信息.它的形式<url>.ism/QualityLevels(3782)/Manifest(video,format=m3u8-aapl-v3,audiotrack=aac_UND_2_192).

谁能解释一下这里发生了什么?