大多数浏览器和
Developer App 均支持流媒体播放。
-
适用于 HTTP Live Streaming 的错误处理最佳做法
HTTP Live Streaming (HLS) 能够在各种不同的网络和带宽条件下稳定传输媒体内容。不过,影响流媒体传输的因素有许多,如服务器或编码器故障、缓存问题或网络掉线。了解您的服务器为实现最高稳定性应采用的最佳行为,并从实践角度了解您的 app 可能遇到的错误以及如何处理这些错误。
资源
相关视频
Tech Talks
WWDC17
-
下载
大家好 欢迎来到 “HTTP实时流 媒体错误处理最佳实践”演讲 我是Shravya Kunamalla 是AVFoundation工程师 让我们开始
很多应用开发者使用我们广受欢迎的 HTTP实时流媒体技术 进行媒体流传输 在过去几年里 这项应用已经演变成为 多种复杂内容传输应用 开发人员进行实时活动直播 和预录视频直播 它们提供多种不同的媒体选择 使用可变比特率 不同的声音和语言字幕 内容本身可能受到保护 可能同时有数百万在线观众 订阅你的流媒体 由于工作负荷巨大 系统会出现错误 过去多年里 许多开发者和内容提供商 总是问我们一个问题 “当发生错误时 应该怎么做?” 为了解答这个问题 今天我们将会介绍 一些错误处理最佳实践 包括在应用端和服务器端
参加本演讲的人 可能都知道HLS传输 让我们进行简要回顾 我们需要一个主播放列表 含有相同内容的不同版本 在本例中 有6MB和2MB视频 英语和法语音频 英语和法语字幕 它们调用一个媒体播放列表 而且有自己的M3UA播放列表
媒体列表包含几个片段 在实际播放中 会在获取播放列表时 定时更新片段列表 这些片段可能会从头开始 新片段被添加到末尾
如果片段受到保护 媒体播放列表也会含有密钥
另外还有会话数据 例如标题或歌词
服务器将发送这些资源 HLS客户端需要它们来进行回放
如果发生错误而导致服务器 不能发送这些数据 应该怎么办? 处理内容和传输错误 的最佳方法是什么?
许多iOS macOS和tvOS客户端 需要从服务器接收这些资源 服务器应该及时交付这些资源 如果交付失败 将会发送相应的 错误代码给AVPlayer 此错误代码应该 清楚地说明错误原因 比如 请求无效 未获得授权 或服务器遇到错误等 比如 由于不支持功能请求 服务器无法执行请求
接下来 让我们来看一些推荐方法 它们用于发送 这些错误信息至AVPlayer
这是一个故障和 错误代码列表 它们是RFC7231中规定的 标准HTTP错误代码 如果片段受到保护 AVPlayer没获得必要的身份验证 将发送401代码
如果客户端没有获得内容授权 将发送403代码
如果临时资源无法使用 例如 将发送404代码
对于永久性资源不可用 将发送410
对于所有异常服务器状况 而没有对应的消息 将发送500代码
大多数内容提供者 CDN是代理服务器中的缓存 它们从其它位置的编码器 获取内容 通知网关的无效响应 将发送502代码
如果服务器处于维护停机 或过载状态 或因其它任何原因不可用 将发送503代码
对于网关超时 将发送504代码
这些错误代码并是新代码 它们已经被沿用很长时间 如果研究这些错误 可以发现 有一类错误是临时性的 比如资源和 服务器临时不可用 从iOS 11开始 我们提供一种方法 使用GAP标记 显式地将这种临时故障 通知给AVPlayer 我们使用EXT-X-GAP 将片段标记为GAP 这可以应用于 一个或多个片段
将此标记放入播放列表 以指示GAP 使AVPlayer能够 进行知情决策
看到此标记后 AVPlayer 将会知道这是临时性故障 可能会决定转向备用内容 或停止播放
如果没有可用内容 AVPlayer最终可能会 播放可用媒体内容 直到错误状态结束并恢复正常
让我们回到故障和错误代码 对于适合使用GAP标记 的错误情况
404临时资源不可用 和503服务器不可用 始终使用GAP标记 请记住 此标记适用于 实时流媒体和回放 但是典型应用一般是实时流媒体 接下来我们将讨论HLS媒体错误情况
当在线回放时 HLS包指定需要定期更新的播放列表 如果服务器无法及时 根据发布的目标持续时间 更新播放列表 我们建议通过发送404代码 向AVPlayer 通知过时的播放列表 可以返回过时的播放列表本身 但是这需要AVplayer 分析过时的播放列表 在分析时 AVPlayer将会尝试各种方法 切换到其它可用内容 或者重试 有些情况下 这可能会用时过长 导致超时 相比之下 发送404 代码 能够更快地将过时播放列表 通知给AVPlayer 这里有另外一个好处 这会立即将过时播放列表 通知给正在加入流媒体的 其它任何新AVPlayer
对于不支持的特性 比如 不支持BYTE-RANGE 则发送501代码
对于所有身份验证失败 发送401代码
接下来我们看一个典型的实时回放例子 我们有两个视频版本 分别为6MB和2MB 还有相应的编码器/包装器 一个提供6MB视频 另一个为服务器提供2MB视频 服务器分发这个内容至 请求内容的HLS客户端 假设网络带宽 足够传输6MB视频 将会获取6MB媒体播放列表 获得应答 然后获取第一个片段 到目前为止 一切正常
突然6MB编码器 或包装器发生故障 长时间停止运行 接下来AVPlayer 重新获取播放列表 服务器将故障信息发送给 AVPlayer客户端 使用GAP标记 对于这个重获取请求 建议服务器发送200 okay代码 媒体播放器中的后续片段 应标记为GAP
AVPlayer在看到这个GAP标记后 切换到2MB视频版本 获取相应的媒体播放列表 继续获取下一个片段 即2MB版本的片段2
这样 可以及时和平滑地切换 从而避免延迟
为了保持向后兼容 对于标记为GAP的任何片段 服务器仍然发送404代码
接下来 我们来看失效转移 什么是失效转移? 它是指主系统发生故障时 待机或备用系统接管工作
我们的服务器提供什么样的失效转移? 一种方法是在备用服务器上 提供冗余的视频内容 将具有相同比特率的 视频存在不同的服务器 并把它们加入到主播放列表之中 当发生错误时 AVPlayer 平滑地进行切换
在切换到停机状态之前 首先会尝试获取备用视频
如果服务器想要显式地触发失效转移 应该发送404代码给列表请求
总之 始终应该使用正确的错误代码 向HLS客户端通知错误信息 将备用播放列表存放在不同服务器 以便在服务器故障时进行失效转移 这种冗余配置是正确的做法
对于不支持的功能 应发送501代码
在实时流媒体应用中 应按照HLS规范及时更新播放列表
对于临时故障 应优先使用GAP标记
应发送404代码指示过时播放列表
现在我们讨论如何处理 AVFoundation错误 发生错误时 正在观看流媒体的用户 需要知道两件事 首先 应该知道发生了错误 其次 需要知道 是什么造成错误的发生 并且预测服务器上的所有错误 应返回AVFoundation 客户端或应用 以及时地响应 AVPlayer发生的 各种错误状况
但是 我们如何确定错误呢?
可通过查看AVPlayer.status 和AVPlayerItem.status 来确定错误
它们将会分别变更为 AVPlayerStatusFailed 和AVPlayerItemStatusFailed 以显示错误状态
要想知道导致故障状态的错误 应查看AVPlayerItem.error
它描述是什么原因 造成内容无法播放
侦听AVPlayerItemFailed ToPlayToEndTimeNotification 以获得内容没有播放结束这一通知
此通知的用户信息字典 包含一个错误对象 它描述问题情况 可以通过 AVPlayerItemFailedToPlay ToEndTimeErrorKey获取
让我们来更深入探究 请查看AVPlayerItem.errorLog
此日志记录 回放期间发生的 所有错误事件
那么 这些错误意味着什么?
它们可能意味着以下四种情况之一: 网络错误、超时、格式错误 和实时播放列表更新错误 网络错误代码是4xx 5xx错误是服务器发送错误 和TCP/IP、DNS错误
请求资源之后 主播放列表、媒体播放列表 媒体文件和密钥可能发生超时错误 无法及时取得回应 将会导致超时错误
不正确的播放列表密钥 和会话数据格式 会导致格式错误
在实时流媒体中 需要根据发布的目标持续时间 更新播放列表 如果未能这样做 将导致实时播放列表更新错误
相应地 AVFoundationDomain错误代码是哪些?
对于网络错误和超时 错误代码是 AVErrorContentIsUnavailable 或AVErrorNoLongerPlayable
AVErrorContentIsUnavailable表示 内容一直不可播放 这意味着身份验证失败 或授权失败
AVErrorNoLongerPlayable 表示内容不可播放 在播放过程中 发生一次或更多次错误 造成无法继续播放
AVErrorFailedToParse 表示分析失败
AVErrorContentNotUpdated表示 播放列表未及时更新
应查看错误的用户信息 以获取基本错误信息 请记住 如果多个错误造成项目失效 错误信息可能是嵌套式的
新错误日志条目 被添加到错误日志时 将发送AVPlayerItem NewErrorLogEntryNotification 因此应该侦听此通知 以获得即时错误通知
这里我要强调一点 AVPlayer将会努力尝试 继续进行回放 切换到不同的可用视频版本 只有不存在可继续回放的视频版本 而且已经播放完缓存内容时 AVPlayerItem.status 才会更改为“失败”
对于所有临时错误 AVPlayer将会 尝试切换和/或重试 如果可以切换到其它视频版本 AVPlayer将会重试一定时间 只有失败后才会放弃 在一定时间之后 将会尝试从备用版本 切换到失效版本 如果网络状况合适
对于永久性错误 例如410 将不会进行重试 AVPlayer仅尝试 切换到不同版本
永久和临时错误代码 符合RFC7231规定的 HTTP错误代码标准
所有会话数据错误 不是关键性的 将会被忽略
接下来 我们来看代码片段 要查看错误 在完成常规工作之 创建你的资产 创建你的播放器项目 使用项目创建播放器 首先要做的是添加侦察器 以跟踪播放器的状态
然后添加侦察器 以跟踪播放器项目的状态
这里你注册并侦听 AVPlayerItemFailed ToPlayToEndTimeNotification
在获得通知之后 项目状态变为错误状态 AVPlayerItem.error 以打印错误信息 在这里 应该添加代码 向用户显示相关的错误信息
获取AVPlayerItemFailed ToPlayToEndTimeNotification 提取错误值AVPlayerItem FailedToPlayToEndTimeErrorKey 然后 采取合适的操作 例如 打印错误或显示相关的错误信息
总结 应始终监测 AVPlayer和AVPlayerItem.status 侦听通知 AVPlayerItemFailed ToPlayToEndTimeNotification 告知用户内容没有播放结束 如果你想要更主动地监测错误 例如 发送调试信息 到服务器以进行分析 应侦听AVPlayerItem NewErrorLogEntryNotification 以获知 已经增加新错误日志条目
总之 当发生错误时 应该采取合适的措施 不要忽略这一点 应该向用户通知错误 在合适情况下 显示有意义的消息或弹出信息
更多信息 请访问WWDC网站 观看演讲514
谢谢并祝大家大会愉快
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。