React+Mobx+videojs重构web直播系统

在正式入职之后接手的第一个重点项目便是web直播系统的重构。因为在实习期间一直参与旧版直播系统的迭代开发,同时因旧版本技术栈相对陈旧、代码维护成本过高、扩展能力较弱等原因,决定于2018年进行彻底重构,针对UI做出重新设计。整体系统比较简单,主体由视频和讨论区两大元素构成,在技术选型上采用React作为UI层框架,Mobx作为状态管理库,videoJs作为视频播放器类库。本文针对重构过程中涉及的主要技术点进行记录,留作今后查缺补漏。

技术选型

Mobx

无论是Redux / MobX ,均是开源的状态管理库,用状态描述 UI 界面,与 React 都不具有强绑定关系

store

Mobx-react 绑定库

主要提供API:Provider & inject & observer

  • redux <-> react-redux
  • mobx <-> mobx-react

装饰器

  • @表示装饰器,可以在 ES7 或者 TypeScript 类属性中使用。Mobx中装饰器的使用并非必须,只是语法稍有区别。
  • Babel默认情况下是不支持装饰器的,需配置相应plugin:

!!注意, plugins 属性中: transform-decorators-legacy 应放在最前面。当使用 react native 时,可用下面的预设来代替 transform-decorators-legacy:

H5的video标签

基本使用

H5中的video标签可以进行视频播放,写一个video设置一个src属性指定媒体源地址就可以实现媒体播放了。针对低版本浏览器video的HTML结构也提供了友好的兼容方案,只需要在video标签内写上不兼容时要展示的HTML内容即可。

video的属性

  • src: 视频地址controls: 控制条;
  • poster: 视频下载时显示的图像;
  • preload: 预加载;
  • playsinline: 防止ios用户视频播放自动全屏。
  • x-webkit-airplay=“allow” : 支持ios的AirPlay功能;
  • x5-video-orientation: 声明播放器支持的方向;
  • x5­-video­-player­-fullscreen:全屏设置;

媒体格式

目前原生H5支持的媒体格式主要有MP4、OGG、WebM、M3U8等,但各大浏览器厂商之间对媒体格式的支持各不相同:

canPlayType API

可以通过HTMLVideoElement的canPlayType API进行当前环境的格式兼容判断:

  • ‘probably’: The specified media type appears to be playable.
  • ‘maybe’: Cannot tell if the media type is playable without playing it.
  • ‘ ‘ :The specified media type definitely cannot be played.

环境差异

    1. UI不一致
    1. API实现与支持程度不一致(标准API里的controls、poster、autoplay…未必有效)
    1. 事件交互行为不一致(播放进度变化、事件触发频率不同、部分事件触发时相应状态值未必可靠、部分场景缺少事件..)
    1. 媒体格式的支持无法保证

Video.js

简介

Video.js 是一个通用的在网页中嵌入视频播放器的 JS 库,自动检测浏览器对 HTML5 的支持情况,如果不支持则自动使用 Flash 播放器。(目前版本:v6.5.0)

优点:

    1. 开源免费(https://github.com/videojs/video.js)。
  • 2.接入简单(几分钟即可完成基础配置,搭建视频页面)。
  • 3.几乎兼容所有主流浏览器,并优先使用html5;在不支持的浏览器中,会自动使用flash进行播放。
    1. 界面可定制、插件可扩展。

注意:

Skins & Icons & Plugins

  • Skinning

播放器样式完全通过html+css构建,可以通过覆盖基础css样式进行调整;

  • Icons

除此之外,videoJS本身固有的几个class如果灵活运用,可以减少部分细节处理工作量

  • vjs-live-control // 展示直播状态
  • vjs-poster // 展示默认图
  • vjs-seeking // 展示加载中loading
  • vjs-controls-enabled // 展示控制条
  • vjs-controls-disabled //隐藏所有的控制组件
  • vjs-ended // 播放结束样式
  • vjs-error // 视频异常展示错误信息
  • Plugins

Video.js 本身很简单,支持基础的播放功能和特性。任何复杂或高级特性将以插件形式提供,比如:播放列表、分析、广告和支持先进的格式如HLS等。(http://videojs.com/plugins/)

Video.js 提供强大而丰富的插件同时,你也可以自己创建插件并发布。

  • 1.插件方法中的this指向所创建plugin依附的videojs实例;

  • 2.插件方法中可以使用任何videojs API进行相关处理;

  • 3.例如在直播系统中:有关视频的日志上报、各种播放器事件监听处理等,均可放到单独的插件中,方便组织代码;

Step 1: Write Some Javascript

Step 2: Registering A Plugin

Step 3: Using A Plugin

初始化

  • 方式一:

  • 方式二:(推荐)

配置参数

一般,对于播放器的初始化,除了传入必备的视频源地址以及视频格式之外,videoJS支持配置额外的options。如:

  • 直播type:’rtmp/flv’
  • 录播type:’video/mp4’

常用API

常用事件

主要事件的处理

  • loadstart:标识播放器开始加载视频,在这里可以展示加载中状态、设置定时器判定首次加载是否成功;

  • error:标识播放器异常,一般原因有网络异常、视频解码异常等,此时进行主动拉流操作,并在多次尝试拉流失败后给出用户提示;

  • canplaythrough、 play、playing、 seeked:都可能标识视频已正常播放,此时应对错误提示、加载中提示、切换线路提示等UI进行隐藏调整;

  • waiting:标识视频发生卡顿较为准确的事件,可以在此处进行视频卡顿次数的记录并展示卡顿提示等信息;

  • pause:标识视频暂停,可以做一些UI(如:预览、控制条等)方面的显隐操作;

  • timeupdate:标识视频进行中位置发生改变,可在此完成协同播放时间的其他界面操作;

  • ended:标识视频播放结束,可做一系列资源回收、清理工作,或者结束提示、循环播放等操作;

  • stalled:标识视频资源不可用,这时应进行主动拉流或者提示用户切换线路等操作(但要注意:在部分浏览器中,视频长时间处于暂停状态后可能也会触发此事件,这是应该忽略);

其他

视频播放监控

视频异常

播放器提供的error事件回调基本涵盖了绝大多数异常情况,包括视频格式无法解析、视频源错误、网络异常、拉流超时等;

视频首次加载过程

当音频/视频处于首次加载过程中时,大致会发生以下事件:

  • 1.play、playing、canplaythrough三个事件不一定都会触发,顺序也并不固定;
  • 2.不同浏览器中(如Edge)可能直接触发到seeked事件即加载完成开始播放,并不会有play、playing、canplaythrough这些;
    1. durationchange有时候会在loadstart事件之前触发;

视频首次加载&卡顿

这里的关键在于定时器到期后判断视频是否处于正常状态

在web直播系统中,我们针对视频首次加载是否成功,视频播放中产生的卡顿进行监测记录:

  • 1.首次加载:从loadstart事件开始若干秒内视频是否加载成功;

  • 2.卡顿:从waiting事件触发后若干秒内是否恢复正常播放;

其他问题小结

Video.networkState() 判断网络状态

  • 0 = NETWORK_EMPTY - 音频/视频尚未初始化
  • 1 = NETWORK_IDLE - 音频/视频是活动的且已选取资源,但并未使用网络
  • 2 = NETWORK_LOADING - 浏览器正在下载数据
  • 3 = NETWORK_NO_SOURCE - 未找到音频/视频来源

在开发中遇到这种情况:直播时,如果web端直接断开网络连接,视频播放器是不会抛出任何异常事件的,这时如果我们想为用户提供主动拉流,需要监测网络状态变化。Video.networkState经试验并不可取,无论网络异常与否,都会从0或2最终变化到1。(最后通过监听offline & online事件获取网络状态变化)

video.addTextTrack()

  • addTextTrack方法创建和返回新的文本轨道。
  • 新的TextTrack对象会被添加到视频/音频元素的文本轨道列表中。

浏览器支持程度:所有主流浏览器都不支持addTextTrack方法。

IE浏览器,每次暂停再开始或快进/退视频,视频倍速会被自动重置为1倍速