作者 | 刘博(又拍云多媒体开发工程师)
当前为了满足比较火热的移动 Web 端直播需求,一系列的 HTML5 直播技术迅速的发展起来。
常见的可用于 HTML5 的直播技术有 HLS、WebSocket 与 WebRTC。今天我向大家介绍WebSocket 与 MSE 相关的技术要点,并在最后通过一个实例来展示具体用法。
文章大纲 WebSocket通常的 Web 应用都是围绕着 HTTP 的请求/响应模型构建的。所有的 HTTP 通信都通过客户端来控制,由客户端向服务器发出一个请求,服务器接收和处理完毕后再返回结果给客户端,客户端将数据展现出来。由于这种模式不能满足实时应用需求,于是出现了 SSE、Comet 等 "服务器推" 的长连接技术。
WebSocket 是基于 TCP 连接之上的通信协议,可以在单个 TCP 连接上进行全双工的通信。WebSocket 在 2011 年被 IETF 定为标准 RFC 6455,并被 RFC 7936 补充规范,WebSocket API 被 W3C 定为标准。
WebSocket 是独立地创建在 TCP 上的协议,HTTP 协议中的那些概念都和 WebSocket 没有关联,唯一关联的是使用 HTTP 协议的 101 状态码进行协议切换时,使用的 TCP 端口是 80,可以绕过大多数防火墙的限制。
WebSocket 握手为了更方便地部署新协议,HTTP/1.1 引入了 Upgrade 机制,使得客户端和服务端之间可以借助已有的HTTP语法升级到其它协议。这个机制在 RFC7230 的 6.7 Upgrade 一节中有详细描述。
要发起 HTTP/1.1 协议升级,客户端必须在请求头部中指定这两个字段 ▽
> Connection: Upgrade Upgrade: protocol-name[/protocol-version]
如果服务端同意升级,那么需要这样响应 ▽
> HTTP/1.1 101 Switching Protocols Connection: upgrade Upgrade: protocol-name[/protocol-version] [... data defined by new protocol ...]
可以看到,HTTP Upgrade 响应的状态码是 101,并且响应正文可以使用新协议定义的数据格式。
WebSocket 握手就利用了这种 HTTP Upgrade 机制。一旦握手完成,后续数据传输直接在 TCP 上完成。
WebSocket JavaScript API目前主流的浏览器提供了 WebSocket 的 API 接口,可以发送消息(文本或者二进制)给服务器,并且接收事件驱动的响应数据。
Step1. 检查浏览器是否支持 WebSocket
> if(window.WebSocket) { // WebSocket代码 }
Step2. 建立连接
> var ws = new WebSocket('ws://localhost:8327');
Step3. 注册回调函数以及收发数据
分别注册 WebSocket 对象的 onopen、onclose、onerror 以及 onmessage 回调函数。
通过ws.send()来进行发送数据,这里不仅可以发送字符串,也可以发送 Blob 或 ArrayBuffer 类型的数据。
如果接收的是二进制数据,需要将连接对象的格式设为 blob 或 arraybuffer。
ws.binaryType = 'arraybuffer';
WebSocket Golang API
服务器端 WebSocket 库我推荐使用 Google 自己的 golang.org/x/net/websocket,可以非常方便的与 net/http 一起使用。也可以将 WebSocket 的 handler function 通过 websocket.Handler转换成 http.Handler,这样就可以跟 net/http 库一起使用了。
然后通过 websocket.Message.Receive 来接收数据,通过 websocket.Message.Send 来发送数据。
具体代码可以看下面的 Demo 部分。
MSE在介绍 MSE 之前,我们先看看 HTML5<audio>和<video> 有哪些限制。
HTML5<audio> 和 <video> 标签的限制
MSE 是解决 HTML5 的流问题。
Media Source Extensions(MSE)是 Chrome、Safari、Edge 等主流浏览器支持的一个新的Web API。MSE 是一个 W3C 标准,允许 JavaScript 动态构建 <video> 和 <audio> 的媒体流。它定义了对象,允许 JavaScript 传输媒体流片段到一个 HTMLMediaElement。
通过使用 MSE,你可以动态地修改媒体流而不需要任何插件。这让前端JavaScript可以做更多的事情—— 在 JavaScript 进行转封装、处理,甚至转码。
虽然 MSE 不能让流直接传输到 media tags 上,但是 MSE 提供了构建跨浏览器播放器的核心技术,让浏览器通过JavaScript API来推音视频到 media tags 上。
Browser Support通过 caniuse 来检查是否浏览器支持情况。
通过 MediaSource.isTypeSupported() 可以进一步地检查 codec MIME 类型是否支持。
fMP4比较常用的视频封装格式有 WebM 和 fMP4。
WebM 和 WebP 是两个姊妹项目,都是由 Google 赞助的。由于 WebM 是基于 Matroska 的容器格式,天生是流式的,很适合用在流媒体领域里。
下面着重介绍一下 fMP4 格式。
我们都知道 MP4 是由一系列的 Boxes 组成的。普通的 MP4 的是嵌套结构的,客户端必须要从头加载一个 MP4 文件,才能够完整播放,不能从中间一段开始播放。
而 fMP4 由一系列的片段组成,如果服务器支持 byte-range 请求,那么,这些片段可以独立的进行请求到客户端进行播放,而不需要加载整个文件。
为了更加形象的说明这一点,下面我介绍几个常用的分析 MP4 文件的工具。
gpac,原名 mp4box,是一个媒体开发框架,在其源码下有大量的媒体分析工具,可以使用testapps;
fragment mp4 VS non-fragment mp4下面是一个 fragment mp4 文件通过 mp4parser(Online MPEG4 Parser )分析后的截图 ▽