实现web端的有感屏幕录制功能,主要依赖以下的webAPI:
Screen Capture API
navigator.mediaDevices.getDisplayMedia:
根据用户授权获取浏览器提供屏幕截取的内容,可以传入参数options来控制约束条件。其中音频属性约束可以不进行捕获,若不传音频约束则不会显示是否分享音频的checkBox,但视频被要求必须进行捕获;displaySurface属性指定了优先使用的屏幕捕获类型,可选属性"broswer"、"monitor"、"window";分别对应当前浏览器窗口、打开的tab页面、整个系统屏幕;具体表现如下图:
当用户选择了分享内容后该方法以promise方式异步返回当前捕获到的mediaStream,利用这个返回的媒体流对象,我们将使用到下一个api来实现录制的相关操作
MediaStream Recording API
MediaRecorder:
通过new MediaRecorder 方法实例化一个录制器对象(recoder),该对象提供了开始录制(start)、暂停录制(pause)、恢复录制(resume)和结束录制(stop)的控制及获取录制数据(requestData)方法;构造函数接收一个mediaStream对象和一个可选的options条件约束;mediaStream刚好可以使用上面API返回的结果,options可以限定录制结果的媒体形式,诸如mimeType或者音视频的采样频率;mediaRecorder另外提供了事件监听dataavailable,可以在recoder状态变活跃(即start方法录制调用)时提供数据缓存,在以下几种条件下会使dataavailable的回调触发:1.录制流被结束掉时;2.recoder.stop调用时;3.recoder.requestData触发;4.start(timeslice)设置了时间切片且达到这个时间点时;在回调中我们可以从BlobEvent中获取到blob格式的录制数据,拿到录制数据后我们就可以按自己的需求的处理啦,比如将blob生成一个url传给video使用,这样就可以在页面上预览录制的效果:
又或者可以作为mp4视频文件直接下载:
然而事情并没有想象中简单,观察下载后的视频文件 发现该文件并没有进度条和总时长....
后来查资料发现这个issue,chromium早在之前的版本已经提过了,奈何一直没有优化,解答当中显示出现这个情况是因为录制的视频文件webm里缺少了时长等参数导致的,解决方案大佬也已经提供:1.使用fix-webm-duration处理录制好的blob数据 2.引用ebmljs处理blob数据
OK~
接下来还需要解决的是会议场景下的问题: 录制时本地的音频开关时获取会议中自身麦克风和远端其他用户讲话的音频数据,混流后作为recorder的流,解决方案是使用下面这个API
Web Audio API
AudioContext.createMediaStreamSource(stream).connect(mediaStreamAudioDestinationNode)
AudioContext.createMediaStreamDestination
初始化创建好mediaStreamAudioDestinationNode,有新的音频流时(比如有本地或远端用户讲话),把stream和destination进行connect,最后把audioDestination.stream.getAudioTracks